Auto merge of #53609 - bemeurer:tidy-ctfe, r=RalfJung
Tidy CFTE/MIRI Fixes #53596
This commit is contained in:
commit
e41f41142b
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::{fmt, env};
|
||||
|
||||
use mir;
|
||||
|
@ -315,7 +325,8 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
|
|||
ReadForeignStatic =>
|
||||
"tried to read from foreign (extern) static",
|
||||
InvalidPointerMath =>
|
||||
"attempted to do invalid arithmetic on pointers that would leak base addresses, e.g. comparing pointers into different allocations",
|
||||
"attempted to do invalid arithmetic on pointers that would leak base addresses, \
|
||||
e.g. comparing pointers into different allocations",
|
||||
ReadUndefBytes =>
|
||||
"attempted to read undefined bytes",
|
||||
DeadLocal =>
|
||||
|
@ -369,11 +380,13 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
|
|||
Layout(_) =>
|
||||
"rustc layout computation failed",
|
||||
UnterminatedCString(_) =>
|
||||
"attempted to get length of a null terminated string, but no null found before end of allocation",
|
||||
"attempted to get length of a null terminated string, but no null found before end \
|
||||
of allocation",
|
||||
HeapAllocZeroBytes =>
|
||||
"tried to re-, de- or allocate zero bytes on the heap",
|
||||
HeapAllocNonPowerOfTwoAlignment(_) =>
|
||||
"tried to re-, de-, or allocate heap memory with alignment that is not a power of two",
|
||||
"tried to re-, de-, or allocate heap memory with alignment that is not a power of \
|
||||
two",
|
||||
Unreachable =>
|
||||
"entered unreachable code",
|
||||
Panic { .. } =>
|
||||
|
@ -435,8 +448,8 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
|
|||
kind, ptr, len, lock)
|
||||
}
|
||||
InvalidMemoryLockRelease { ptr, len, frame, ref lock } => {
|
||||
write!(f, "frame {} tried to release memory write lock at {:?}, size {}, but cannot release lock {:?}",
|
||||
frame, ptr, len, lock)
|
||||
write!(f, "frame {} tried to release memory write lock at {:?}, size {}, but \
|
||||
cannot release lock {:?}", frame, ptr, len, lock)
|
||||
}
|
||||
DeallocatedLockedMemory { ptr, ref lock } => {
|
||||
write!(f, "tried to deallocate memory at {:?} in conflict with lock {:?}",
|
||||
|
@ -447,7 +460,8 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
|
|||
}
|
||||
NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
|
||||
FunctionPointerTyMismatch(sig, got) =>
|
||||
write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig, got),
|
||||
write!(f, "tried to call a function with sig {} through a \
|
||||
function pointer of type {}", sig, got),
|
||||
BoundsCheck { ref len, ref index } =>
|
||||
write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
|
||||
ReallocatedWrongMemoryKind(ref old, ref new) =>
|
||||
|
@ -470,7 +484,8 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
|
|||
MachineError(ref inner) =>
|
||||
write!(f, "{}", inner),
|
||||
IncorrectAllocationInformation(size, size2, align, align2) =>
|
||||
write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size.bytes(), align.abi(), size2.bytes(), align2.abi()),
|
||||
write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and \
|
||||
align {}", size.bytes(), align.abi(), size2.bytes(), align2.abi()),
|
||||
Panic { ref msg, line, col, ref file } =>
|
||||
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
|
||||
_ => write!(f, "{}", self.description()),
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! An interpreter for MIR used in CTFE and by miri
|
||||
|
||||
#[macro_export]
|
||||
|
@ -40,7 +50,8 @@ use std::num::NonZeroU32;
|
|||
pub enum Lock {
|
||||
NoLock,
|
||||
WriteLock(DynamicLifetime),
|
||||
/// This should never be empty -- that would be a read lock held and nobody there to release it...
|
||||
/// This should never be empty -- that would be a read lock held and nobody
|
||||
/// there to release it...
|
||||
ReadLock(Vec<DynamicLifetime>),
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(unknown_lints)]
|
||||
|
||||
use ty::layout::{HasDataLayout, Size};
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::ty::{self, Ty, TypeAndMut};
|
||||
use rustc::ty::layout::{self, TyLayout, Size};
|
||||
use syntax::ast::{FloatTy, IntTy, UintTy};
|
||||
|
@ -216,7 +226,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
Ok(Scalar::Bits { bits: v, size: 4 })
|
||||
},
|
||||
|
||||
// No alignment check needed for raw pointers. But we have to truncate to target ptr size.
|
||||
// No alignment check needed for raw pointers.
|
||||
// But we have to truncate to target ptr size.
|
||||
RawPtr(_) => {
|
||||
Ok(Scalar::Bits {
|
||||
bits: self.memory.truncate_to_ptr(v).0 as u128,
|
||||
|
@ -229,7 +240,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
fn cast_from_float(&self, bits: u128, fty: FloatTy, dest_ty: Ty<'tcx>) -> EvalResult<'tcx, Scalar> {
|
||||
fn cast_from_float(
|
||||
&self,
|
||||
bits: u128,
|
||||
fty: FloatTy,
|
||||
dest_ty: Ty<'tcx>
|
||||
) -> EvalResult<'tcx, Scalar> {
|
||||
use rustc::ty::TyKind::*;
|
||||
use rustc_apfloat::FloatConvert;
|
||||
match dest_ty.sty {
|
||||
|
@ -292,7 +308,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
fn cast_from_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Scalar> {
|
||||
use rustc::ty::TyKind::*;
|
||||
match ty.sty {
|
||||
// Casting to a reference or fn pointer is not permitted by rustc, no need to support it here.
|
||||
// Casting to a reference or fn pointer is not permitted by rustc,
|
||||
// no need to support it here.
|
||||
RawPtr(_) |
|
||||
Int(IntTy::Isize) |
|
||||
Uint(UintTy::Usize) => Ok(ptr.into()),
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::fmt;
|
||||
use std::error::Error;
|
||||
|
||||
|
@ -462,7 +472,8 @@ fn to_str<'a, 'tcx, 'mir>(
|
|||
if let Value::ScalarPair(ptr, len) = val {
|
||||
let len = len.not_undef()?.to_bits(ecx.memory.pointer_size())?;
|
||||
let bytes = ecx.memory.read_bytes(ptr.not_undef()?, Size::from_bytes(len as u64))?;
|
||||
let str = ::std::str::from_utf8(bytes).map_err(|err| EvalErrorKind::ValidationFailure(err.to_string()))?;
|
||||
let str = ::std::str::from_utf8(bytes)
|
||||
.map_err(|err| EvalErrorKind::ValidationFailure(err.to_string()))?;
|
||||
Ok(Symbol::intern(str))
|
||||
} else {
|
||||
bug!("panic arg is not a str")
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
|
@ -82,7 +92,8 @@ pub struct Frame<'mir, 'tcx: 'mir> {
|
|||
pub return_place: Place,
|
||||
|
||||
/// The list of locals for this stack frame, stored in order as
|
||||
/// `[return_ptr, arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
|
||||
/// `[return_ptr, arguments..., variables..., temporaries...]`.
|
||||
/// The locals are stored as `Option<Value>`s.
|
||||
/// `None` represents a local that is currently dead, while a live local
|
||||
/// can either directly contain `Scalar` or refer to some part of an `Allocation`.
|
||||
pub locals: IndexVec<mir::Local, LocalValue>,
|
||||
|
@ -269,7 +280,9 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'mir, 'tcx, M> {
|
||||
impl<'a, 'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'mir, 'tcx, M>
|
||||
where M: Machine<'mir, 'tcx>
|
||||
{
|
||||
#[inline]
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
|
||||
*self.tcx
|
||||
|
@ -329,7 +342,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
|
||||
pub(crate) fn with_fresh_body<F: FnOnce(&mut Self) -> R, R>(&mut self, f: F) -> R {
|
||||
let stack = mem::replace(&mut self.stack, Vec::new());
|
||||
let steps = mem::replace(&mut self.steps_since_detector_enabled, -STEPS_UNTIL_DETECTOR_ENABLED);
|
||||
let steps = mem::replace(&mut self.steps_since_detector_enabled,
|
||||
-STEPS_UNTIL_DETECTOR_ENABLED);
|
||||
let r = f(self);
|
||||
self.stack = stack;
|
||||
self.steps_since_detector_enabled = steps;
|
||||
|
@ -378,7 +392,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
Ok(Value::new_slice(Scalar::Ptr(ptr), s.len() as u64, self.tcx.tcx))
|
||||
}
|
||||
|
||||
pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, ty::Instance<'tcx>> {
|
||||
pub(super) fn resolve(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
substs: &'tcx Substs<'tcx>
|
||||
) -> EvalResult<'tcx, ty::Instance<'tcx>> {
|
||||
trace!("resolve: {:?}, {:#?}", def_id, substs);
|
||||
trace!("substs: {:#?}", self.substs());
|
||||
trace!("param_env: {:#?}", self.param_env);
|
||||
|
@ -405,7 +423,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
) -> EvalResult<'tcx, &'tcx mir::Mir<'tcx>> {
|
||||
// do not continue if typeck errors occurred (can only occur in local crate)
|
||||
let did = instance.def_id();
|
||||
if did.is_local() && self.tcx.has_typeck_tables(did) && self.tcx.typeck_tables_of(did).tainted_by_errors {
|
||||
if did.is_local()
|
||||
&& self.tcx.has_typeck_tables(did)
|
||||
&& self.tcx.typeck_tables_of(did).tainted_by_errors
|
||||
{
|
||||
return err!(TypeckError);
|
||||
}
|
||||
trace!("load mir {:?}", instance);
|
||||
|
@ -614,7 +635,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
match frame.return_to_block {
|
||||
StackPopCleanup::MarkStatic(mutable) => {
|
||||
if let Place::Ptr(MemPlace { ptr, .. }) = frame.return_place {
|
||||
// FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
|
||||
// FIXME: to_ptr()? might be too extreme here,
|
||||
// static zsts might reach this under certain conditions
|
||||
self.memory.mark_static_initialized(
|
||||
ptr.to_ptr()?.alloc_id,
|
||||
mutable,
|
||||
|
@ -651,7 +673,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
} else {
|
||||
self.param_env
|
||||
};
|
||||
self.tcx.const_eval(param_env.and(gid)).map_err(|err| EvalErrorKind::ReferencedConstant(err).into())
|
||||
self.tcx.const_eval(param_env.and(gid))
|
||||
.map_err(|err| EvalErrorKind::ReferencedConstant(err).into())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -757,7 +780,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
} else {
|
||||
last_span = Some(span);
|
||||
}
|
||||
let location = if self.tcx.def_key(instance.def_id()).disambiguated_data.data == DefPathData::ClosureExpr {
|
||||
let location = if self.tcx.def_key(instance.def_id()).disambiguated_data.data
|
||||
== DefPathData::ClosureExpr
|
||||
{
|
||||
"closure".to_owned()
|
||||
} else {
|
||||
instance.to_string()
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! This module contains everything needed to instantiate an interpreter.
|
||||
//! This separation exists to ensure that no fancy miri features like
|
||||
//! interpreting common C functions leak into CTFE.
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The memory subsystem.
|
||||
//!
|
||||
//! Generally, we use `Pointer` to denote memory addresses. However, some operations
|
||||
|
@ -231,13 +241,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
}
|
||||
};
|
||||
|
||||
let alloc_kind = self.alloc_kind.remove(&ptr.alloc_id).expect("alloc_map out of sync with alloc_kind");
|
||||
let alloc_kind = self.alloc_kind
|
||||
.remove(&ptr.alloc_id)
|
||||
.expect("alloc_map out of sync with alloc_kind");
|
||||
|
||||
// It is okay for us to still holds locks on deallocation -- for example, we could store data we own
|
||||
// in a local, and the local could be deallocated (from StorageDead) before the function returns.
|
||||
// However, we should check *something*. For now, we make sure that there is no conflicting write
|
||||
// lock by another frame. We *have* to permit deallocation if we hold a read lock.
|
||||
// TODO: Figure out the exact rules here.
|
||||
// It is okay for us to still holds locks on deallocation -- for example, we could store
|
||||
// data we own in a local, and the local could be deallocated (from StorageDead) before the
|
||||
// function returns. However, we should check *something*. For now, we make sure that there
|
||||
// is no conflicting write lock by another frame. We *have* to permit deallocation if we
|
||||
// hold a read lock.
|
||||
// FIXME: Figure out the exact rules here.
|
||||
M::free_lock(self, ptr.alloc_id, alloc.bytes.len() as u64)?;
|
||||
|
||||
if alloc_kind != kind {
|
||||
|
@ -248,7 +261,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
}
|
||||
if let Some((size, align)) = size_and_align {
|
||||
if size.bytes() != alloc.bytes.len() as u64 || align != alloc.align {
|
||||
return err!(IncorrectAllocationInformation(size, Size::from_bytes(alloc.bytes.len() as u64), align, alloc.align));
|
||||
let bytes = Size::from_bytes(alloc.bytes.len() as u64);
|
||||
return err!(IncorrectAllocationInformation(size,
|
||||
bytes,
|
||||
align,
|
||||
alloc.align));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,13 +528,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
size: Size,
|
||||
align: Align,
|
||||
) -> EvalResult<'tcx, &[u8]> {
|
||||
// Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL
|
||||
// Zero-sized accesses can use dangling pointers,
|
||||
// but they still have to be aligned and non-NULL
|
||||
self.check_align(ptr.into(), align)?;
|
||||
if size.bytes() == 0 {
|
||||
return Ok(&[]);
|
||||
}
|
||||
M::check_locks(self, ptr, size, AccessKind::Read)?;
|
||||
self.check_bounds(ptr.offset(size, self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
|
||||
// if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
|
||||
self.check_bounds(ptr.offset(size, self)?, true)?;
|
||||
let alloc = self.get(ptr.alloc_id)?;
|
||||
assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
|
||||
assert_eq!(size.bytes() as usize as u64, size.bytes());
|
||||
|
@ -532,13 +551,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
size: Size,
|
||||
align: Align,
|
||||
) -> EvalResult<'tcx, &mut [u8]> {
|
||||
// Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL
|
||||
// Zero-sized accesses can use dangling pointers,
|
||||
// but they still have to be aligned and non-NULL
|
||||
self.check_align(ptr.into(), align)?;
|
||||
if size.bytes() == 0 {
|
||||
return Ok(&mut []);
|
||||
}
|
||||
M::check_locks(self, ptr, size, AccessKind::Write)?;
|
||||
self.check_bounds(ptr.offset(size, &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
|
||||
// if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
|
||||
self.check_bounds(ptr.offset(size, &*self)?, true)?;
|
||||
let alloc = self.get_mut(ptr.alloc_id)?;
|
||||
assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
|
||||
assert_eq!(size.bytes() as usize as u64, size.bytes());
|
||||
|
@ -663,7 +684,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
relocations
|
||||
.iter()
|
||||
.map(|&(offset, alloc_id)| {
|
||||
(offset + dest.offset - src.offset + (i * size * relocations.len() as u64), alloc_id)
|
||||
(offset + dest.offset - src.offset + (i * size * relocations.len() as u64),
|
||||
alloc_id)
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -692,11 +714,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
}
|
||||
|
||||
for i in 0..length {
|
||||
ptr::copy(src_bytes, dest_bytes.offset((size.bytes() * i) as isize), size.bytes() as usize);
|
||||
ptr::copy(src_bytes,
|
||||
dest_bytes.offset((size.bytes() * i) as isize),
|
||||
size.bytes() as usize);
|
||||
}
|
||||
} else {
|
||||
for i in 0..length {
|
||||
ptr::copy_nonoverlapping(src_bytes, dest_bytes.offset((size.bytes() * i) as isize), size.bytes() as usize);
|
||||
ptr::copy_nonoverlapping(src_bytes,
|
||||
dest_bytes.offset((size.bytes() * i) as isize),
|
||||
size.bytes() as usize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -763,15 +789,22 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
}
|
||||
|
||||
/// Read a *non-ZST* scalar
|
||||
pub fn read_scalar(&self, ptr: Pointer, ptr_align: Align, size: Size) -> EvalResult<'tcx, ScalarMaybeUndef> {
|
||||
self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer
|
||||
pub fn read_scalar(
|
||||
&self,
|
||||
ptr: Pointer,
|
||||
ptr_align: Align,
|
||||
size: Size
|
||||
) -> EvalResult<'tcx, ScalarMaybeUndef> {
|
||||
// Make sure we don't read part of a pointer as a pointer
|
||||
self.check_relocation_edges(ptr, size)?;
|
||||
let endianness = self.endianness();
|
||||
// get_bytes_unchecked tests alignment
|
||||
let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?;
|
||||
// Undef check happens *after* we established that the alignment is correct.
|
||||
// We must not return Ok() for unaligned pointers!
|
||||
if self.check_defined(ptr, size).is_err() {
|
||||
// this inflates undefined bytes to the entire scalar, even if only a few bytes are undefined
|
||||
// this inflates undefined bytes to the entire scalar,
|
||||
// even if only a few bytes are undefined
|
||||
return Ok(ScalarMaybeUndef::Undef);
|
||||
}
|
||||
// Now we do the actual reading
|
||||
|
@ -784,7 +817,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
} else {
|
||||
let alloc = self.get(ptr.alloc_id)?;
|
||||
match alloc.relocations.get(&ptr.offset) {
|
||||
Some(&alloc_id) => return Ok(ScalarMaybeUndef::Scalar(Pointer::new(alloc_id, Size::from_bytes(bits as u64)).into())),
|
||||
Some(&alloc_id) => {
|
||||
let ptr = Pointer::new(alloc_id, Size::from_bytes(bits as u64));
|
||||
return Ok(ScalarMaybeUndef::Scalar(ptr.into()))
|
||||
}
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
|
@ -795,7 +831,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
}))
|
||||
}
|
||||
|
||||
pub fn read_ptr_sized(&self, ptr: Pointer, ptr_align: Align) -> EvalResult<'tcx, ScalarMaybeUndef> {
|
||||
pub fn read_ptr_sized(&self, ptr: Pointer, ptr_align: Align)
|
||||
-> EvalResult<'tcx, ScalarMaybeUndef> {
|
||||
self.read_scalar(ptr, ptr_align, self.pointer_size())
|
||||
}
|
||||
|
||||
|
@ -848,7 +885,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_ptr_sized(&mut self, ptr: Pointer, ptr_align: Align, val: ScalarMaybeUndef) -> EvalResult<'tcx> {
|
||||
pub fn write_ptr_sized(&mut self, ptr: Pointer, ptr_align: Align, val: ScalarMaybeUndef)
|
||||
-> EvalResult<'tcx> {
|
||||
let ptr_size = self.pointer_size();
|
||||
self.write_scalar(ptr.into(), ptr_align, val, ptr_size)
|
||||
}
|
||||
|
@ -992,7 +1030,9 @@ pub trait HasMemory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
|
|||
fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M>;
|
||||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasMemory<'a, 'mir, 'tcx, M> for Memory<'a, 'mir, 'tcx, M> {
|
||||
impl<'a, 'mir, 'tcx, M> HasMemory<'a, 'mir, 'tcx, M> for Memory<'a, 'mir, 'tcx, M>
|
||||
where M: Machine<'mir, 'tcx>
|
||||
{
|
||||
#[inline]
|
||||
fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
|
||||
self
|
||||
|
@ -1004,7 +1044,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasMemory<'a, 'mir, 'tcx, M> for Me
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasMemory<'a, 'mir, 'tcx, M> for EvalContext<'a, 'mir, 'tcx, M> {
|
||||
impl<'a, 'mir, 'tcx, M> HasMemory<'a, 'mir, 'tcx, M> for EvalContext<'a, 'mir, 'tcx, M>
|
||||
where M: Machine<'mir, 'tcx>
|
||||
{
|
||||
#[inline]
|
||||
fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
|
||||
&mut self.memory
|
||||
|
@ -1016,7 +1058,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasMemory<'a, 'mir, 'tcx, M> for Ev
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasDataLayout for &'a Memory<'a, 'mir, 'tcx, M> {
|
||||
impl<'a, 'mir, 'tcx, M> layout::HasDataLayout for &'a Memory<'a, 'mir, 'tcx, M>
|
||||
where M: Machine<'mir, 'tcx>
|
||||
{
|
||||
#[inline]
|
||||
fn data_layout(&self) -> &TargetDataLayout {
|
||||
&self.tcx.data_layout
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! An interpreter for MIR used in CTFE and by miri
|
||||
|
||||
mod cast;
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Functions concerning immediate values and operands, and reading from operands.
|
||||
//! All high-level functions to read from memory work on operands as sources.
|
||||
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, layout::{self, TyLayout}};
|
||||
use syntax::ast::FloatTy;
|
||||
|
@ -58,7 +68,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
layout::Abi::Scalar(ref scalar) => scalar.value,
|
||||
_ => return err!(TypeNotPrimitive(right_layout.ty)),
|
||||
};
|
||||
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, left, left_kind, right, right_kind);
|
||||
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
||||
bin_op, left, left_kind, right, right_kind);
|
||||
|
||||
// I: Handle operations that support pointers
|
||||
if !left_kind.is_float() && !right_kind.is_float() {
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Computations on places -- field projections, going from mir::Place, and writing
|
||||
//! into a place.
|
||||
//! All high-level functions to write to memory work on places as destinations.
|
||||
|
@ -109,8 +119,9 @@ impl MemPlace {
|
|||
/// Extract the ptr part of the mplace
|
||||
#[inline(always)]
|
||||
pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
|
||||
// At this point, we forget about the alignment information -- the place has been turned into a reference,
|
||||
// and no matter where it came from, it now must be aligned.
|
||||
// At this point, we forget about the alignment information --
|
||||
// the place has been turned into a reference, and no matter where it came from,
|
||||
// it now must be aligned.
|
||||
self.to_scalar_ptr_align().0.to_ptr()
|
||||
}
|
||||
|
||||
|
@ -276,11 +287,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
offsets[usize::try_from(field).unwrap()],
|
||||
layout::FieldPlacement::Array { stride, .. } => {
|
||||
let len = base.len();
|
||||
assert!(field < len, "Tried to access element {} of array/slice with length {}", field, len);
|
||||
assert!(field < len,
|
||||
"Tried to access element {} of array/slice with length {}", field, len);
|
||||
stride * field
|
||||
}
|
||||
layout::FieldPlacement::Union(count) => {
|
||||
assert!(field < count as u64, "Tried to access field {} of union with {} fields", field, count);
|
||||
assert!(field < count as u64,
|
||||
"Tried to access field {} of union with {} fields", field, count);
|
||||
// Offset is always 0
|
||||
Size::from_bytes(0)
|
||||
}
|
||||
|
@ -572,9 +585,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
dest: MPlaceTy<'tcx>,
|
||||
) -> EvalResult<'tcx> {
|
||||
let (ptr, ptr_align) = dest.to_scalar_ptr_align();
|
||||
// Note that it is really important that the type here is the right one, and matches the type things are read at.
|
||||
// In case `src_val` is a `ScalarPair`, we don't do any magic here to handle padding properly, which is only
|
||||
// correct if we never look at this data with the wrong type.
|
||||
// Note that it is really important that the type here is the right one, and matches the
|
||||
// type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here
|
||||
// to handle padding properly, which is only correct if we never look at this data with the
|
||||
// wrong type.
|
||||
|
||||
// Nothing to do for ZSTs, other than checking alignment
|
||||
if dest.layout.size.bytes() == 0 {
|
||||
|
@ -592,7 +606,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
Value::ScalarPair(a_val, b_val) => {
|
||||
let (a, b) = match dest.layout.abi {
|
||||
layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
|
||||
_ => bug!("write_value_to_mplace: invalid ScalarPair layout: {:#?}", dest.layout)
|
||||
_ => bug!("write_value_to_mplace: invalid ScalarPair layout: {:#?}",
|
||||
dest.layout)
|
||||
};
|
||||
let (a_size, b_size) = (a.size(&self), b.size(&self));
|
||||
let (a_align, b_align) = (a.align(&self), b.align(&self));
|
||||
|
@ -758,7 +773,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
/// Turn a place that is a dyn trait (i.e., PlaceExtra::Vtable and the appropriate layout)
|
||||
/// or a slice into the specific fixed-size place and layout that is given by the vtable/len.
|
||||
/// This "unpacks" the existential quantifier, so to speak.
|
||||
pub fn unpack_unsized_mplace(&self, mplace: MPlaceTy<'tcx>) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
|
||||
pub fn unpack_unsized_mplace(
|
||||
&self,
|
||||
mplace: MPlaceTy<'tcx>
|
||||
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
|
||||
trace!("Unpacking {:?} ({:?})", *mplace, mplace.layout.ty);
|
||||
let layout = match mplace.extra {
|
||||
PlaceExtra::Vtable(vtable) => {
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! This module contains the `EvalContext` methods for executing a single step of the interpreter.
|
||||
//!
|
||||
//! The main entry point is the `step` method.
|
||||
|
@ -98,8 +108,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
|
||||
use rustc::mir::StatementKind::*;
|
||||
|
||||
// Some statements (e.g. box) push new stack frames. We have to record the stack frame number
|
||||
// *before* executing the statement.
|
||||
// Some statements (e.g. box) push new stack frames.
|
||||
// We have to record the stack frame number *before* executing the statement.
|
||||
let frame_idx = self.cur_frame();
|
||||
self.tcx.span = stmt.source_info.span;
|
||||
self.memory.tcx.span = stmt.source_info.span;
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::mir::BasicBlock;
|
||||
use rustc::ty::{self, layout::LayoutOf};
|
||||
use syntax::source_map::Span;
|
||||
|
@ -14,9 +24,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
target: BasicBlock,
|
||||
) -> EvalResult<'tcx> {
|
||||
trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance);
|
||||
// We take the address of the object. This may well be unaligned, which is fine for us here.
|
||||
// However, unaligned accesses will probably make the actual drop implementation fail -- a problem shared
|
||||
// by rustc.
|
||||
// We take the address of the object. This may well be unaligned, which is fine for us
|
||||
// here. However, unaligned accesses will probably make the actual drop implementation fail
|
||||
// -- a problem shared by rustc.
|
||||
let place = self.force_allocation(place)?;
|
||||
|
||||
let (instance, place) = match place.layout.ty.sty {
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::layout::LayoutOf;
|
||||
|
@ -45,7 +55,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
|
||||
for (index, &const_int) in values.iter().enumerate() {
|
||||
// Compare using binary_op
|
||||
let const_int = Scalar::Bits { bits: const_int, size: discr.layout.size.bytes() as u8 };
|
||||
let const_int = Scalar::Bits {
|
||||
bits: const_int,
|
||||
size: discr.layout.size.bytes() as u8
|
||||
};
|
||||
let (res, _) = self.binary_op(mir::BinOp::Eq,
|
||||
discr,
|
||||
ValTy { value: Value::Scalar(const_int.into()), layout: discr.layout }
|
||||
|
@ -144,7 +157,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
target,
|
||||
..
|
||||
} => {
|
||||
let cond_val = self.eval_operand_and_read_value(cond, None)?.to_scalar()?.to_bool()?;
|
||||
let cond_val = self.eval_operand_and_read_value(cond, None)?
|
||||
.to_scalar()?
|
||||
.to_bool()?;
|
||||
if expected == cond_val {
|
||||
self.goto_block(target);
|
||||
} else {
|
||||
|
@ -175,15 +190,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
DropAndReplace { .. } => unimplemented!(),
|
||||
Resume => unimplemented!(),
|
||||
Abort => unimplemented!(),
|
||||
FalseEdges { .. } => bug!("should have been eliminated by `simplify_branches` mir pass"),
|
||||
FalseUnwind { .. } => bug!("should have been eliminated by `simplify_branches` mir pass"),
|
||||
FalseEdges { .. } => bug!("should have been eliminated by\
|
||||
`simplify_branches` mir pass"),
|
||||
FalseUnwind { .. } => bug!("should have been eliminated by\
|
||||
`simplify_branches` mir pass"),
|
||||
Unreachable => return err!(Unreachable),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Decides whether it is okay to call the method with signature `real_sig` using signature `sig`.
|
||||
/// Decides whether it is okay to call the method with signature `real_sig`
|
||||
/// using signature `sig`.
|
||||
/// FIXME: This should take into account the platform-dependent ABI description.
|
||||
fn check_sig_compat(
|
||||
&mut self,
|
||||
|
@ -197,7 +215,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
return match (&ty.sty, &real_ty.sty) {
|
||||
// Permit changing the pointer type of raw pointers and references as well as
|
||||
// mutability of raw pointers.
|
||||
// TODO: Should not be allowed when fat pointers are involved.
|
||||
// FIXME: Should not be allowed when fat pointers are involved.
|
||||
(&ty::RawPtr(_), &ty::RawPtr(_)) => true,
|
||||
(&ty::Ref(_, _, _), &ty::Ref(_, _, _)) => {
|
||||
ty.is_mutable_pointer() == real_ty.is_mutable_pointer()
|
||||
|
@ -226,7 +244,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
// We need to allow what comes up when a non-capturing closure is cast to a fn().
|
||||
match (sig.abi, real_sig.abi) {
|
||||
(Abi::Rust, Abi::RustCall) // check the ABIs. This makes the test here non-symmetric.
|
||||
if check_ty_compat(sig.output(), real_sig.output()) && real_sig.inputs_and_output.len() == 3 => {
|
||||
if check_ty_compat(sig.output(), real_sig.output())
|
||||
&& real_sig.inputs_and_output.len() == 3 => {
|
||||
// First argument of real_sig must be a ZST
|
||||
let fst_ty = real_sig.inputs_and_output[0];
|
||||
if self.layout_of(fst_ty)?.is_zst() {
|
||||
|
@ -234,7 +253,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
let snd_ty = real_sig.inputs_and_output[1];
|
||||
match snd_ty.sty {
|
||||
ty::Tuple(tys) if sig.inputs().len() == tys.len() =>
|
||||
if sig.inputs().iter().zip(tys).all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) {
|
||||
if sig.inputs()
|
||||
.iter()
|
||||
.zip(tys)
|
||||
.all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) {
|
||||
return Ok(true)
|
||||
},
|
||||
_ => {}
|
||||
|
@ -291,7 +313,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
trace!(
|
||||
"args: {:#?}",
|
||||
self.frame().mir.args_iter().zip(args.iter())
|
||||
.map(|(local, arg)| (local, **arg, arg.layout.ty)).collect::<Vec<_>>()
|
||||
.map(|(local, arg)| (local, **arg, arg.layout.ty))
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
let local = arg_locals.nth(1).unwrap();
|
||||
for (i, &op) in args.into_iter().enumerate() {
|
||||
|
@ -312,7 +335,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
ty::InstanceDef::Item(_) => {
|
||||
// Push the stack frame, and potentially be entirely done if the call got hooked
|
||||
if M::eval_fn_call(self, instance, destination, args, span)? {
|
||||
// TODO: Can we make it return the frame to push, instead
|
||||
// FIXME: Can we make it return the frame to push, instead
|
||||
// of the hook doing half of the work and us doing the argument
|
||||
// initialization?
|
||||
return Ok(());
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::layout::{Size, Align, LayoutOf};
|
||||
use rustc::mir::interpret::{Scalar, Pointer, EvalResult};
|
||||
|
@ -82,7 +92,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
) -> EvalResult<'tcx, (Size, Align)> {
|
||||
let pointer_size = self.memory.pointer_size();
|
||||
let pointer_align = self.tcx.data_layout.pointer_align;
|
||||
let size = self.memory.read_ptr_sized(vtable.offset(pointer_size, self)?, pointer_align)?.to_bits(pointer_size)? as u64;
|
||||
let size = self.memory.read_ptr_sized(vtable.offset(pointer_size, self)?,pointer_align)?
|
||||
.to_bits(pointer_size)? as u64;
|
||||
let align = self.memory.read_ptr_sized(
|
||||
vtable.offset(pointer_size * 2, self)?,
|
||||
pointer_align
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
use syntax_pos::symbol::Symbol;
|
||||
|
@ -211,7 +221,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
let variant = self.read_discriminant_as_variant_index(dest.into())?;
|
||||
let inner_dest = self.mplace_downcast(dest, variant)?;
|
||||
// Put the variant projection onto the path, as a field
|
||||
path.push(PathElem::Field(dest.layout.ty.ty_adt_def().unwrap().variants[variant].name));
|
||||
path.push(PathElem::Field(dest.layout.ty
|
||||
.ty_adt_def()
|
||||
.unwrap()
|
||||
.variants[variant].name));
|
||||
trace!("variant layout: {:#?}", dest.layout);
|
||||
(variant, inner_dest)
|
||||
},
|
||||
|
@ -255,7 +268,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
if value.layout.ty.builtin_deref(false).is_some() {
|
||||
trace!("Recursing below ptr {:#?}", value);
|
||||
let ptr_place = self.ref_to_mplace(value)?;
|
||||
// we have not encountered this pointer+layout combination before
|
||||
// we have not encountered this pointer+layout
|
||||
// combination before
|
||||
if seen.insert(ptr_place) {
|
||||
todo.push((ptr_place, path_clone_and_deref(path)));
|
||||
}
|
||||
|
|
|
@ -76,8 +76,6 @@ fn filter_dirs(path: &Path) -> bool {
|
|||
"src/tools/miri",
|
||||
"src/tools/lld",
|
||||
"src/tools/lldb",
|
||||
"src/librustc/mir/interpret",
|
||||
"src/librustc_mir/interpret",
|
||||
"src/target",
|
||||
"src/stdsimd",
|
||||
];
|
||||
|
|
Loading…
Reference in New Issue