2016-12-07 20:30:37 -08:00
|
|
|
use std::cell::Ref;
|
|
|
|
use std::collections::HashMap;
|
2017-02-07 00:39:40 -08:00
|
|
|
use std::fmt::Write;
|
2016-12-07 20:30:37 -08:00
|
|
|
|
2016-04-14 00:01:00 +02:00
|
|
|
use rustc::hir::def_id::DefId;
|
2016-09-28 18:22:53 +02:00
|
|
|
use rustc::hir::map::definitions::DefPathData;
|
2016-12-07 20:30:37 -08:00
|
|
|
use rustc::middle::const_val::ConstVal;
|
2016-11-03 10:38:08 +01:00
|
|
|
use rustc::mir;
|
2016-08-27 01:44:46 -06:00
|
|
|
use rustc::traits::Reveal;
|
2016-04-23 00:03:59 -06:00
|
|
|
use rustc::ty::layout::{self, Layout, Size};
|
2016-03-28 17:43:23 -06:00
|
|
|
use rustc::ty::subst::{self, Subst, Substs};
|
2016-09-08 10:25:45 +02:00
|
|
|
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
2016-06-11 12:38:28 -06:00
|
|
|
use rustc_data_structures::indexed_vec::Idx;
|
2016-06-23 01:03:58 -06:00
|
|
|
use syntax::codemap::{self, DUMMY_SP};
|
2015-11-12 15:50:58 -06:00
|
|
|
|
2016-03-18 23:03:46 -06:00
|
|
|
use error::{EvalError, EvalResult};
|
2016-12-07 20:58:48 -08:00
|
|
|
use lvalue::{Global, GlobalId, Lvalue, LvalueExtra};
|
2016-10-21 10:32:27 +02:00
|
|
|
use memory::{Memory, Pointer};
|
2016-12-10 16:23:07 -08:00
|
|
|
use operator;
|
2016-12-21 17:15:03 -08:00
|
|
|
use value::{PrimVal, PrimValKind, Value};
|
2016-06-01 17:05:20 +02:00
|
|
|
|
2016-11-26 19:18:39 -08:00
|
|
|
pub type MirRef<'tcx> = Ref<'tcx, mir::Mir<'tcx>>;
|
2016-11-03 10:38:08 +01:00
|
|
|
|
2016-06-10 16:20:17 +02:00
|
|
|
pub struct EvalContext<'a, 'tcx: 'a> {
|
2016-03-14 21:18:39 -06:00
|
|
|
/// The results of the type checker, from rustc.
|
2017-02-10 13:35:45 -08:00
|
|
|
pub(crate) tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
2016-03-14 21:18:39 -06:00
|
|
|
|
|
|
|
/// The virtual memory system.
|
2017-02-10 13:35:45 -08:00
|
|
|
pub(crate) memory: Memory<'a, 'tcx>,
|
2016-03-14 21:18:39 -06:00
|
|
|
|
2016-06-14 20:13:59 -06:00
|
|
|
/// Precomputed statics, constants and promoteds.
|
2017-02-10 13:35:45 -08:00
|
|
|
pub(crate) globals: HashMap<GlobalId<'tcx>, Global<'tcx>>,
|
2016-05-09 18:21:21 -06:00
|
|
|
|
|
|
|
/// The virtual call stack.
|
2017-02-10 13:35:45 -08:00
|
|
|
pub(crate) stack: Vec<Frame<'tcx>>,
|
2016-07-05 13:23:58 +02:00
|
|
|
|
|
|
|
/// The maximum number of stack frames allowed
|
2017-02-10 13:35:45 -08:00
|
|
|
pub(crate) stack_limit: usize,
|
2016-11-17 17:22:34 +01:00
|
|
|
|
|
|
|
/// The maximum number of operations that may be executed.
|
|
|
|
/// This prevents infinite loops and huge computations from freezing up const eval.
|
|
|
|
/// Remove once halting problem is solved.
|
2017-02-10 13:35:45 -08:00
|
|
|
pub(crate) steps_remaining: u64,
|
2016-05-09 18:21:21 -06:00
|
|
|
}
|
|
|
|
|
2016-03-06 04:23:24 -06:00
|
|
|
/// A stack frame.
|
2016-11-03 10:38:08 +01:00
|
|
|
pub struct Frame<'tcx> {
|
2016-06-14 20:13:59 -06:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Function and callsite information
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2016-06-02 18:21:32 +02:00
|
|
|
|
2016-06-14 20:13:59 -06:00
|
|
|
/// The MIR for the function called on this frame.
|
2016-11-03 10:38:08 +01:00
|
|
|
pub mir: MirRef<'tcx>,
|
2016-06-14 20:13:59 -06:00
|
|
|
|
|
|
|
/// The def_id of the current function.
|
|
|
|
pub def_id: DefId,
|
2016-06-02 18:21:32 +02:00
|
|
|
|
2016-06-14 20:13:59 -06:00
|
|
|
/// type substitutions for the current function invocation.
|
2016-06-10 13:01:51 +02:00
|
|
|
pub substs: &'tcx Substs<'tcx>,
|
2016-06-02 18:21:32 +02:00
|
|
|
|
2016-06-14 20:13:59 -06:00
|
|
|
/// The span of the call site.
|
|
|
|
pub span: codemap::Span,
|
2016-03-07 07:10:52 -06:00
|
|
|
|
2016-06-14 20:13:59 -06:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2016-10-15 19:48:30 -06:00
|
|
|
// Return lvalue and locals
|
2016-06-14 20:13:59 -06:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2016-03-14 20:39:51 -06:00
|
|
|
|
2016-07-06 17:55:05 +02:00
|
|
|
/// The block to return to when returning from the current stack frame
|
2016-09-09 17:44:04 +02:00
|
|
|
pub return_to_block: StackPopCleanup,
|
2016-07-06 17:55:05 +02:00
|
|
|
|
2016-10-15 19:48:30 -06:00
|
|
|
/// The location where the result of the current stack frame should be written to.
|
2016-10-21 10:29:56 +02:00
|
|
|
pub return_lvalue: Lvalue<'tcx>,
|
2016-10-15 19:48:30 -06:00
|
|
|
|
|
|
|
/// The list of locals for this stack frame, stored in order as
|
|
|
|
/// `[arguments..., variables..., temporaries...]`. The locals are stored as `Value`s, which
|
|
|
|
/// can either directly contain `PrimVal` or refer to some part of an `Allocation`.
|
2016-10-15 23:31:42 -06:00
|
|
|
///
|
2016-12-18 20:59:01 -08:00
|
|
|
/// Before being initialized, all locals are `Value::ByVal(PrimVal::Undef)`.
|
|
|
|
pub locals: Vec<Value>,
|
2016-02-27 19:20:25 -06:00
|
|
|
|
2016-12-07 09:52:22 +01:00
|
|
|
/// Temporary allocations introduced to save stackframes
|
2016-12-06 18:13:11 +01:00
|
|
|
/// This is pure interpreter magic and has nothing to do with how rustc does it
|
|
|
|
/// An example is calling an FnMut closure that has been converted to a FnOnce closure
|
2017-02-14 15:35:03 +01:00
|
|
|
/// The value's destructor will be called and the memory freed when the stackframe finishes
|
|
|
|
pub interpreter_temporaries: Vec<(Pointer, Ty<'tcx>)>,
|
2016-12-06 18:13:11 +01:00
|
|
|
|
2016-06-14 20:13:59 -06:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Current position within the function
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
/// The block that is currently executed (or will be executed after the above call stacks
|
|
|
|
/// return).
|
|
|
|
pub block: mir::BasicBlock,
|
|
|
|
|
|
|
|
/// The index of the currently evaluated statment.
|
2016-06-10 13:01:51 +02:00
|
|
|
pub stmt: usize,
|
2016-03-06 04:23:24 -06:00
|
|
|
}
|
2016-02-27 19:20:25 -06:00
|
|
|
|
2016-09-09 17:44:04 +02:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
|
|
|
pub enum StackPopCleanup {
|
2016-10-21 11:48:56 +02:00
|
|
|
/// The stackframe existed to compute the initial value of a static/constant, make sure it
|
2017-02-07 19:20:16 +01:00
|
|
|
/// isn't modifyable afterwards in case of constants.
|
|
|
|
/// In case of `static mut`, mark the memory to ensure it's never marked as immutable through
|
|
|
|
/// references or deallocated
|
|
|
|
/// The bool decides whether the value is mutable (true) or not (false)
|
|
|
|
MarkStatic(bool),
|
2016-09-09 17:44:04 +02:00
|
|
|
/// A regular stackframe added due to a function call will need to get forwarded to the next
|
|
|
|
/// block
|
|
|
|
Goto(mir::BasicBlock),
|
|
|
|
/// The main function and diverging functions have nowhere to return to
|
|
|
|
None,
|
|
|
|
}
|
|
|
|
|
2016-11-26 17:54:19 -08:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub struct ResourceLimits {
|
|
|
|
pub memory_size: u64,
|
|
|
|
pub step_limit: u64,
|
|
|
|
pub stack_limit: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for ResourceLimits {
|
|
|
|
fn default() -> Self {
|
|
|
|
ResourceLimits {
|
|
|
|
memory_size: 100 * 1024 * 1024, // 100 MB
|
|
|
|
step_limit: 1_000_000,
|
|
|
|
stack_limit: 100,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-10 16:20:17 +02:00
|
|
|
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
2016-11-26 17:54:19 -08:00
|
|
|
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, limits: ResourceLimits) -> Self {
|
2016-06-10 16:20:17 +02:00
|
|
|
EvalContext {
|
2017-01-16 18:45:30 -08:00
|
|
|
tcx,
|
2016-11-26 17:54:19 -08:00
|
|
|
memory: Memory::new(&tcx.data_layout, limits.memory_size),
|
2016-10-21 11:39:39 +02:00
|
|
|
globals: HashMap::new(),
|
2016-06-09 16:01:53 +02:00
|
|
|
stack: Vec::new(),
|
2016-11-26 17:54:19 -08:00
|
|
|
stack_limit: limits.stack_limit,
|
|
|
|
steps_remaining: limits.step_limit,
|
2016-03-06 04:23:24 -06:00
|
|
|
}
|
|
|
|
}
|
2016-06-01 14:33:37 +02:00
|
|
|
|
2016-10-16 00:12:11 -06:00
|
|
|
pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, Pointer> {
|
|
|
|
let substs = self.substs();
|
|
|
|
self.alloc_ptr_with_substs(ty, substs)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn alloc_ptr_with_substs(
|
2016-10-14 03:31:45 -06:00
|
|
|
&mut self,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
substs: &'tcx Substs<'tcx>
|
|
|
|
) -> EvalResult<'tcx, Pointer> {
|
2016-11-17 17:23:40 +01:00
|
|
|
let size = self.type_size_with_substs(ty, substs)?.expect("cannot alloc memory for unsized type");
|
|
|
|
let align = self.type_align_with_substs(ty, substs)?;
|
2016-08-27 01:44:46 -06:00
|
|
|
self.memory.allocate(size, align)
|
2016-06-08 09:38:59 +02:00
|
|
|
}
|
2016-06-08 11:11:08 +02:00
|
|
|
|
2016-06-30 11:29:25 +02:00
|
|
|
pub fn memory(&self) -> &Memory<'a, 'tcx> {
|
2016-06-10 13:01:51 +02:00
|
|
|
&self.memory
|
|
|
|
}
|
|
|
|
|
2016-06-23 09:36:24 +02:00
|
|
|
pub fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx> {
|
2016-06-15 12:55:04 +02:00
|
|
|
&mut self.memory
|
|
|
|
}
|
|
|
|
|
2016-11-03 10:38:08 +01:00
|
|
|
pub fn stack(&self) -> &[Frame<'tcx>] {
|
2016-06-10 13:01:51 +02:00
|
|
|
&self.stack
|
|
|
|
}
|
|
|
|
|
2017-02-10 13:35:33 -08:00
|
|
|
pub(crate) fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
|
|
|
|
let ptr = self.memory.allocate_cached(s.as_bytes())?;
|
2017-01-12 08:28:42 +01:00
|
|
|
Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128)))
|
2016-09-23 10:38:30 +02:00
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn const_to_value(&mut self, const_val: &ConstVal) -> EvalResult<'tcx, Value> {
|
2016-06-08 09:38:59 +02:00
|
|
|
use rustc::middle::const_val::ConstVal::*;
|
2016-10-20 04:42:19 -06:00
|
|
|
use rustc_const_math::ConstFloat;
|
2016-09-19 02:19:31 -06:00
|
|
|
|
|
|
|
let primval = match *const_val {
|
2017-01-12 08:28:42 +01:00
|
|
|
Integral(const_int) => PrimVal::Bytes(const_int.to_u128_unchecked()),
|
2016-10-20 04:42:19 -06:00
|
|
|
|
|
|
|
Float(ConstFloat::F32(f)) => PrimVal::from_f32(f),
|
|
|
|
Float(ConstFloat::F64(f)) => PrimVal::from_f64(f),
|
|
|
|
|
|
|
|
Bool(b) => PrimVal::from_bool(b),
|
|
|
|
Char(c) => PrimVal::from_char(c),
|
2016-09-23 10:38:30 +02:00
|
|
|
|
2016-09-26 17:49:30 +02:00
|
|
|
Str(ref s) => return self.str_to_value(s),
|
2016-09-19 02:19:31 -06:00
|
|
|
|
2016-06-08 09:38:59 +02:00
|
|
|
ByteStr(ref bs) => {
|
2017-02-10 13:35:33 -08:00
|
|
|
let ptr = self.memory.allocate_cached(bs)?;
|
2016-12-15 23:55:00 -08:00
|
|
|
PrimVal::Ptr(ptr)
|
2016-06-08 09:38:59 +02:00
|
|
|
}
|
2016-09-19 02:19:31 -06:00
|
|
|
|
|
|
|
Struct(_) => unimplemented!(),
|
|
|
|
Tuple(_) => unimplemented!(),
|
2017-03-02 13:11:33 +01:00
|
|
|
Function(_, _) => unimplemented!(),
|
2017-02-06 09:26:01 -08:00
|
|
|
Array(_) => unimplemented!(),
|
2016-09-19 02:19:31 -06:00
|
|
|
Repeat(_, _) => unimplemented!(),
|
|
|
|
};
|
|
|
|
|
2016-09-26 17:49:30 +02:00
|
|
|
Ok(Value::ByVal(primval))
|
2016-06-08 09:38:59 +02:00
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
|
2016-09-07 18:34:59 +02:00
|
|
|
// generics are weird, don't run this function on a generic
|
2016-09-08 10:25:45 +02:00
|
|
|
assert!(!ty.needs_subst());
|
2016-06-08 09:38:59 +02:00
|
|
|
ty.is_sized(self.tcx, &self.tcx.empty_parameter_environment(), DUMMY_SP)
|
|
|
|
}
|
|
|
|
|
2016-11-03 10:38:08 +01:00
|
|
|
pub fn load_mir(&self, def_id: DefId) -> EvalResult<'tcx, MirRef<'tcx>> {
|
2016-09-27 17:01:06 +02:00
|
|
|
trace!("load mir {:?}", def_id);
|
2016-11-03 10:38:08 +01:00
|
|
|
if def_id.is_local() || self.tcx.sess.cstore.is_item_mir_available(def_id) {
|
|
|
|
Ok(self.tcx.item_mir(def_id))
|
2016-08-27 01:44:46 -06:00
|
|
|
} else {
|
2016-11-03 10:38:08 +01:00
|
|
|
Err(EvalError::NoMirFor(self.tcx.item_path_str(def_id)))
|
2016-06-06 15:22:33 +02:00
|
|
|
}
|
|
|
|
}
|
2016-06-08 11:11:08 +02:00
|
|
|
|
2016-06-30 11:29:25 +02:00
|
|
|
pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
|
2017-01-28 15:28:24 +01:00
|
|
|
// miri doesn't care about lifetimes, and will choke on some crazy ones
|
|
|
|
// let's simply get rid of them
|
|
|
|
let without_lifetimes = self.tcx.erase_regions(&ty);
|
|
|
|
let substituted = without_lifetimes.subst(self.tcx, substs);
|
2016-11-26 23:37:38 -08:00
|
|
|
self.tcx.normalize_associated_type(&substituted)
|
2016-06-08 11:11:08 +02:00
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn type_size(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<u64>> {
|
2016-06-13 11:24:01 +02:00
|
|
|
self.type_size_with_substs(ty, self.substs())
|
2016-06-08 11:11:08 +02:00
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn type_align(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, u64> {
|
2016-07-05 14:27:27 +02:00
|
|
|
self.type_align_with_substs(ty, self.substs())
|
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
fn type_size_with_substs(
|
|
|
|
&self,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
substs: &'tcx Substs<'tcx>,
|
|
|
|
) -> EvalResult<'tcx, Option<u64>> {
|
2016-11-17 17:23:40 +01:00
|
|
|
let layout = self.type_layout_with_substs(ty, substs)?;
|
2016-11-11 13:07:41 +01:00
|
|
|
if layout.is_unsized() {
|
2016-11-17 17:23:40 +01:00
|
|
|
Ok(None)
|
2016-11-11 13:07:41 +01:00
|
|
|
} else {
|
2016-11-18 12:55:14 +01:00
|
|
|
Ok(Some(layout.size(&self.tcx.data_layout).bytes()))
|
2016-11-11 13:07:41 +01:00
|
|
|
}
|
2016-06-13 11:24:01 +02:00
|
|
|
}
|
|
|
|
|
2016-11-18 12:55:14 +01:00
|
|
|
fn type_align_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, u64> {
|
|
|
|
self.type_layout_with_substs(ty, substs).map(|layout| layout.align(&self.tcx.data_layout).abi())
|
2016-07-05 14:27:27 +02:00
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn type_layout(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, &'tcx Layout> {
|
2016-06-13 11:24:01 +02:00
|
|
|
self.type_layout_with_substs(ty, self.substs())
|
|
|
|
}
|
|
|
|
|
2016-11-17 17:23:40 +01:00
|
|
|
fn type_layout_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, &'tcx Layout> {
|
2016-06-08 11:11:08 +02:00
|
|
|
// TODO(solson): Is this inefficient? Needs investigation.
|
|
|
|
let ty = self.monomorphize(ty, substs);
|
|
|
|
|
2017-01-13 17:16:19 +01:00
|
|
|
self.tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
|
2016-11-17 17:23:40 +01:00
|
|
|
ty.layout(&infcx).map_err(EvalError::Layout)
|
2016-06-08 11:11:08 +02:00
|
|
|
})
|
|
|
|
}
|
2016-03-06 04:23:24 -06:00
|
|
|
|
2016-07-05 10:47:10 +02:00
|
|
|
pub fn push_stack_frame(
|
|
|
|
&mut self,
|
|
|
|
def_id: DefId,
|
|
|
|
span: codemap::Span,
|
2016-11-03 10:38:08 +01:00
|
|
|
mir: MirRef<'tcx>,
|
2016-07-05 10:47:10 +02:00
|
|
|
substs: &'tcx Substs<'tcx>,
|
2016-10-21 10:29:56 +02:00
|
|
|
return_lvalue: Lvalue<'tcx>,
|
2016-09-09 17:44:04 +02:00
|
|
|
return_to_block: StackPopCleanup,
|
2017-02-14 15:35:03 +01:00
|
|
|
temporaries: Vec<(Pointer, Ty<'tcx>)>,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2016-05-30 18:09:52 +02:00
|
|
|
::log_settings::settings().indentation += 1;
|
|
|
|
|
2016-10-15 23:31:42 -06:00
|
|
|
// Subtract 1 because `local_decls` includes the ReturnPointer, but we don't store a local
|
|
|
|
// `Value` for that.
|
|
|
|
let num_locals = mir.local_decls.len() - 1;
|
2016-12-18 20:59:01 -08:00
|
|
|
let locals = vec![Value::ByVal(PrimVal::Undef); num_locals];
|
2016-06-09 17:23:58 +02:00
|
|
|
|
2016-03-07 07:10:52 -06:00
|
|
|
self.stack.push(Frame {
|
2017-01-16 18:45:30 -08:00
|
|
|
mir,
|
2016-06-14 20:13:59 -06:00
|
|
|
block: mir::START_BLOCK,
|
2017-01-16 18:45:30 -08:00
|
|
|
return_to_block,
|
|
|
|
return_lvalue,
|
|
|
|
locals,
|
2016-12-06 18:13:11 +01:00
|
|
|
interpreter_temporaries: temporaries,
|
2017-01-16 18:45:30 -08:00
|
|
|
span,
|
|
|
|
def_id,
|
|
|
|
substs,
|
2016-06-03 16:57:47 +02:00
|
|
|
stmt: 0,
|
2016-03-06 04:23:24 -06:00
|
|
|
});
|
2016-10-15 19:48:30 -06:00
|
|
|
|
2016-07-05 13:23:58 +02:00
|
|
|
if self.stack.len() > self.stack_limit {
|
|
|
|
Err(EvalError::StackFrameLimitReached)
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
2015-11-12 15:50:58 -06:00
|
|
|
}
|
|
|
|
|
2017-02-04 13:09:10 -08:00
|
|
|
pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
|
2016-05-30 18:09:52 +02:00
|
|
|
::log_settings::settings().indentation -= 1;
|
2016-07-06 17:55:05 +02:00
|
|
|
let frame = self.stack.pop().expect("tried to pop a stack frame, but there were none");
|
2016-09-09 17:44:04 +02:00
|
|
|
match frame.return_to_block {
|
2017-02-07 19:20:16 +01:00
|
|
|
StackPopCleanup::MarkStatic(mutable) => if let Lvalue::Global(id) = frame.return_lvalue {
|
2016-12-18 20:59:01 -08:00
|
|
|
let global_value = self.globals.get_mut(&id)
|
2017-02-07 20:28:54 +01:00
|
|
|
.expect("global should have been cached (static)");
|
2016-12-18 20:59:01 -08:00
|
|
|
match global_value.value {
|
2017-02-08 16:27:28 +01:00
|
|
|
Value::ByRef(ptr) => self.memory.mark_static_initalized(ptr.alloc_id, mutable)?,
|
2016-12-17 01:47:24 -08:00
|
|
|
Value::ByVal(val) => if let PrimVal::Ptr(ptr) = val {
|
2017-02-08 16:27:28 +01:00
|
|
|
self.memory.mark_static_initalized(ptr.alloc_id, mutable)?;
|
2016-11-17 14:48:34 +01:00
|
|
|
},
|
2016-12-17 01:47:24 -08:00
|
|
|
Value::ByValPair(val1, val2) => {
|
|
|
|
if let PrimVal::Ptr(ptr) = val1 {
|
2017-02-08 16:27:28 +01:00
|
|
|
self.memory.mark_static_initalized(ptr.alloc_id, mutable)?;
|
2016-11-17 14:48:34 +01:00
|
|
|
}
|
2016-12-17 01:47:24 -08:00
|
|
|
if let PrimVal::Ptr(ptr) = val2 {
|
2017-02-08 16:27:28 +01:00
|
|
|
self.memory.mark_static_initalized(ptr.alloc_id, mutable)?;
|
2016-11-17 14:48:34 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
2017-02-08 15:32:49 +01:00
|
|
|
// see comment on `initialized` field
|
|
|
|
assert!(!global_value.initialized);
|
|
|
|
global_value.initialized = true;
|
2016-10-21 11:48:56 +02:00
|
|
|
assert!(global_value.mutable);
|
2017-02-07 19:20:16 +01:00
|
|
|
global_value.mutable = mutable;
|
2016-10-21 10:32:27 +02:00
|
|
|
} else {
|
2017-02-07 20:28:54 +01:00
|
|
|
bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_lvalue);
|
2016-10-21 10:32:27 +02:00
|
|
|
},
|
2016-09-09 17:44:04 +02:00
|
|
|
StackPopCleanup::Goto(target) => self.goto_block(target),
|
|
|
|
StackPopCleanup::None => {},
|
2016-07-06 17:55:05 +02:00
|
|
|
}
|
2016-11-18 10:35:41 +01:00
|
|
|
// deallocate all locals that are backed by an allocation
|
2017-01-22 00:19:35 -08:00
|
|
|
for local in frame.locals {
|
2016-12-18 20:59:01 -08:00
|
|
|
if let Value::ByRef(ptr) = local {
|
2016-12-07 09:19:14 +01:00
|
|
|
trace!("deallocating local");
|
2016-12-07 22:00:46 -08:00
|
|
|
self.memory.dump_alloc(ptr.alloc_id);
|
2016-11-17 14:48:34 +01:00
|
|
|
match self.memory.deallocate(ptr) {
|
2017-02-07 20:28:54 +01:00
|
|
|
// We could alternatively check whether the alloc_id is static before calling
|
|
|
|
// deallocate, but this is much simpler and is probably the rare case.
|
2017-02-07 19:20:16 +01:00
|
|
|
Ok(()) | Err(EvalError::DeallocatedStaticMemory) => {},
|
2016-11-17 14:48:34 +01:00
|
|
|
other => return other,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-02-14 15:35:03 +01:00
|
|
|
// drop and deallocate all temporary allocations
|
|
|
|
for (ptr, ty) in frame.interpreter_temporaries {
|
|
|
|
trace!("dropping temporary allocation");
|
|
|
|
let mut drops = Vec::new();
|
|
|
|
self.drop(Lvalue::from_ptr(ptr), ty, &mut drops)?;
|
|
|
|
self.eval_drop_impls(drops, frame.span)?;
|
2016-12-07 09:19:14 +01:00
|
|
|
}
|
2016-09-09 17:44:04 +02:00
|
|
|
Ok(())
|
2016-03-06 04:23:24 -06:00
|
|
|
}
|
|
|
|
|
2016-12-19 17:26:47 +01:00
|
|
|
pub fn assign_discr_and_fields<
|
|
|
|
V: IntoValTyPair<'tcx>,
|
|
|
|
J: IntoIterator<Item = V>,
|
|
|
|
>(
|
2016-03-28 21:08:08 -06:00
|
|
|
&mut self,
|
2016-10-21 10:29:56 +02:00
|
|
|
dest: Lvalue<'tcx>,
|
2017-02-13 11:58:42 +01:00
|
|
|
dest_ty: Ty<'tcx>,
|
|
|
|
discr_offset: u64,
|
2016-12-19 17:26:47 +01:00
|
|
|
operands: J,
|
|
|
|
discr_val: u128,
|
2017-02-13 11:58:42 +01:00
|
|
|
variant_idx: usize,
|
2016-12-19 17:26:47 +01:00
|
|
|
discr_size: u64,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2016-12-19 17:26:47 +01:00
|
|
|
// FIXME(solson)
|
|
|
|
let dest_ptr = self.force_allocation(dest)?.to_ptr();
|
|
|
|
|
|
|
|
let discr_dest = dest_ptr.offset(discr_offset);
|
|
|
|
self.memory.write_uint(discr_dest, discr_val, discr_size)?;
|
|
|
|
|
2017-02-13 11:58:42 +01:00
|
|
|
let dest = Lvalue::Ptr {
|
|
|
|
ptr: dest_ptr,
|
|
|
|
extra: LvalueExtra::DowncastVariant(variant_idx),
|
|
|
|
};
|
|
|
|
|
|
|
|
self.assign_fields(dest, dest_ty, operands)
|
2016-12-19 17:26:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn assign_fields<
|
|
|
|
V: IntoValTyPair<'tcx>,
|
|
|
|
J: IntoIterator<Item = V>,
|
|
|
|
>(
|
|
|
|
&mut self,
|
|
|
|
dest: Lvalue<'tcx>,
|
2017-02-13 11:58:42 +01:00
|
|
|
dest_ty: Ty<'tcx>,
|
2016-12-19 17:26:47 +01:00
|
|
|
operands: J,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2017-02-13 11:58:42 +01:00
|
|
|
for (field_index, operand) in operands.into_iter().enumerate() {
|
2016-12-19 17:26:47 +01:00
|
|
|
let (value, value_ty) = operand.into_val_ty_pair(self)?;
|
2017-02-13 11:58:42 +01:00
|
|
|
let field_dest = self.lvalue_field(dest, field_index, dest_ty, value_ty)?;
|
|
|
|
self.write_value(value, field_dest, value_ty)?;
|
2016-03-12 22:15:59 -06:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2016-09-19 02:19:31 -06:00
|
|
|
/// Evaluate an assignment statement.
|
|
|
|
///
|
|
|
|
/// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
|
|
|
|
/// type writes its results directly into the memory specified by the lvalue.
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn eval_rvalue_into_lvalue(
|
2016-09-19 02:19:31 -06:00
|
|
|
&mut self,
|
|
|
|
rvalue: &mir::Rvalue<'tcx>,
|
|
|
|
lvalue: &mir::Lvalue<'tcx>,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2016-10-14 03:31:45 -06:00
|
|
|
let dest = self.eval_lvalue(lvalue)?;
|
2016-04-07 05:56:07 -06:00
|
|
|
let dest_ty = self.lvalue_ty(lvalue);
|
2016-11-17 17:23:40 +01:00
|
|
|
let dest_layout = self.type_layout(dest_ty)?;
|
2015-11-20 15:54:02 -06:00
|
|
|
|
2016-11-03 10:38:08 +01:00
|
|
|
use rustc::mir::Rvalue::*;
|
2015-11-12 16:13:35 -06:00
|
|
|
match *rvalue {
|
2016-03-07 03:32:02 -06:00
|
|
|
Use(ref operand) => {
|
2016-09-19 02:19:31 -06:00
|
|
|
let value = self.eval_operand(operand)?;
|
|
|
|
self.write_value(value, dest, dest_ty)?;
|
2016-02-27 19:20:25 -06:00
|
|
|
}
|
2015-11-20 15:54:02 -06:00
|
|
|
|
2016-03-13 01:43:28 -06:00
|
|
|
BinaryOp(bin_op, ref left, ref right) => {
|
2016-06-20 16:52:43 +02:00
|
|
|
// ignore overflow bit, rustc inserts check branches for us
|
2016-11-26 22:58:01 -08:00
|
|
|
self.intrinsic_overflowing(bin_op, left, right, dest, dest_ty)?;
|
2016-03-13 01:43:28 -06:00
|
|
|
}
|
2016-03-07 07:10:52 -06:00
|
|
|
|
2016-06-11 13:10:42 -06:00
|
|
|
CheckedBinaryOp(bin_op, ref left, ref right) => {
|
2016-10-16 17:18:06 -06:00
|
|
|
self.intrinsic_with_overflow(bin_op, left, right, dest, dest_ty)?;
|
2016-06-11 13:10:42 -06:00
|
|
|
}
|
2016-06-11 12:38:28 -06:00
|
|
|
|
2016-03-07 07:57:08 -06:00
|
|
|
UnaryOp(un_op, ref operand) => {
|
2016-09-19 02:19:31 -06:00
|
|
|
let val = self.eval_operand_to_primval(operand)?;
|
2016-11-26 22:58:01 -08:00
|
|
|
let kind = self.ty_to_primval_kind(dest_ty)?;
|
2016-12-10 16:23:07 -08:00
|
|
|
self.write_primval(dest, operator::unary_op(un_op, val, kind)?, dest_ty)?;
|
2016-03-07 07:57:08 -06:00
|
|
|
}
|
2016-03-04 23:17:31 -06:00
|
|
|
|
2017-02-13 13:46:39 +01:00
|
|
|
// Skip everything for zsts
|
|
|
|
Aggregate(..) if self.type_size(dest_ty)? == Some(0) => {}
|
|
|
|
|
2016-03-12 22:15:59 -06:00
|
|
|
Aggregate(ref kind, ref operands) => {
|
2016-11-17 17:22:34 +01:00
|
|
|
self.inc_step_counter_and_check_limit(operands.len() as u64)?;
|
2016-05-08 19:29:00 -06:00
|
|
|
use rustc::ty::layout::Layout::*;
|
2016-04-23 00:03:59 -06:00
|
|
|
match *dest_layout {
|
2016-05-08 19:29:00 -06:00
|
|
|
Univariant { ref variant, .. } => {
|
2017-01-30 09:44:52 +01:00
|
|
|
if variant.packed {
|
|
|
|
let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
|
|
|
|
self.memory.mark_packed(ptr, variant.stride().bytes());
|
|
|
|
}
|
2017-02-13 11:58:42 +01:00
|
|
|
self.assign_fields(dest, dest_ty, operands)?;
|
2016-04-23 00:03:59 -06:00
|
|
|
}
|
|
|
|
|
2016-05-08 19:29:00 -06:00
|
|
|
Array { .. } => {
|
2017-02-13 11:58:42 +01:00
|
|
|
self.assign_fields(dest, dest_ty, operands)?;
|
2016-03-28 21:08:08 -06:00
|
|
|
}
|
2016-03-20 23:09:27 -06:00
|
|
|
|
2016-05-08 19:29:00 -06:00
|
|
|
General { discr, ref variants, .. } => {
|
2016-09-06 16:04:51 +02:00
|
|
|
if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind {
|
2017-03-02 13:11:33 +01:00
|
|
|
let discr_val = adt_def.discriminants(self.tcx)
|
|
|
|
.nth(variant)
|
|
|
|
.expect("broken mir: Adt variant id invalid")
|
|
|
|
.to_u128_unchecked();
|
2016-11-18 12:55:14 +01:00
|
|
|
let discr_size = discr.size().bytes();
|
2017-01-30 09:44:52 +01:00
|
|
|
if variants[variant].packed {
|
|
|
|
let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
|
|
|
|
self.memory.mark_packed(ptr, variants[variant].stride().bytes());
|
|
|
|
}
|
2016-10-14 03:31:45 -06:00
|
|
|
|
2016-12-19 17:26:47 +01:00
|
|
|
self.assign_discr_and_fields(
|
|
|
|
dest,
|
2017-02-13 11:58:42 +01:00
|
|
|
dest_ty,
|
|
|
|
variants[variant].offsets[0].bytes(),
|
2016-12-19 17:26:47 +01:00
|
|
|
operands,
|
|
|
|
discr_val,
|
2017-02-13 11:58:42 +01:00
|
|
|
variant,
|
2016-12-19 17:26:47 +01:00
|
|
|
discr_size,
|
|
|
|
)?;
|
2016-04-23 00:03:59 -06:00
|
|
|
} else {
|
2016-09-06 16:16:49 +02:00
|
|
|
bug!("tried to assign {:?} to Layout::General", kind);
|
2016-03-15 05:50:53 -06:00
|
|
|
}
|
2016-04-30 01:04:17 -06:00
|
|
|
}
|
|
|
|
|
2016-05-08 19:29:00 -06:00
|
|
|
RawNullablePointer { nndiscr, .. } => {
|
2016-09-06 16:04:51 +02:00
|
|
|
if let mir::AggregateKind::Adt(_, variant, _, _) = *kind {
|
2016-04-30 01:04:17 -06:00
|
|
|
if nndiscr == variant as u64 {
|
|
|
|
assert_eq!(operands.len(), 1);
|
|
|
|
let operand = &operands[0];
|
2016-09-19 02:19:31 -06:00
|
|
|
let value = self.eval_operand(operand)?;
|
|
|
|
let value_ty = self.operand_ty(operand);
|
|
|
|
self.write_value(value, dest, value_ty)?;
|
2016-04-30 01:04:17 -06:00
|
|
|
} else {
|
2016-11-15 16:15:17 +01:00
|
|
|
if let Some(operand) = operands.get(0) {
|
|
|
|
assert_eq!(operands.len(), 1);
|
|
|
|
let operand_ty = self.operand_ty(operand);
|
2016-11-17 17:23:40 +01:00
|
|
|
assert_eq!(self.type_size(operand_ty)?, Some(0));
|
2016-11-15 16:15:17 +01:00
|
|
|
}
|
2016-12-18 23:31:23 -08:00
|
|
|
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
|
2016-04-30 01:04:17 -06:00
|
|
|
}
|
|
|
|
} else {
|
2016-09-06 16:16:49 +02:00
|
|
|
bug!("tried to assign {:?} to Layout::RawNullablePointer", kind);
|
2016-03-15 05:50:53 -06:00
|
|
|
}
|
2016-04-23 00:03:59 -06:00
|
|
|
}
|
|
|
|
|
2016-12-21 17:23:28 -08:00
|
|
|
StructWrappedNullablePointer { nndiscr, ref nonnull, ref discrfield, .. } => {
|
2016-09-06 16:04:51 +02:00
|
|
|
if let mir::AggregateKind::Adt(_, variant, _, _) = *kind {
|
2017-01-30 09:44:52 +01:00
|
|
|
if nonnull.packed {
|
|
|
|
let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
|
|
|
|
self.memory.mark_packed(ptr, nonnull.stride().bytes());
|
|
|
|
}
|
2016-05-25 00:37:52 -06:00
|
|
|
if nndiscr == variant as u64 {
|
2017-02-13 11:58:42 +01:00
|
|
|
self.assign_fields(dest, dest_ty, operands)?;
|
2016-05-25 00:37:52 -06:00
|
|
|
} else {
|
2016-09-27 17:02:04 +02:00
|
|
|
for operand in operands {
|
|
|
|
let operand_ty = self.operand_ty(operand);
|
2016-11-17 17:23:40 +01:00
|
|
|
assert_eq!(self.type_size(operand_ty)?, Some(0));
|
2016-09-27 17:02:04 +02:00
|
|
|
}
|
2016-11-11 13:10:47 +01:00
|
|
|
let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
|
2016-10-14 03:31:45 -06:00
|
|
|
|
|
|
|
// FIXME(solson)
|
2016-10-15 19:48:30 -06:00
|
|
|
let dest = self.force_allocation(dest)?.to_ptr();
|
2016-10-14 03:31:45 -06:00
|
|
|
|
2016-11-18 12:55:14 +01:00
|
|
|
let dest = dest.offset(offset.bytes());
|
2016-12-18 20:59:01 -08:00
|
|
|
let dest_size = self.type_size(ty)?
|
|
|
|
.expect("bad StructWrappedNullablePointer discrfield");
|
2016-12-07 22:56:28 -08:00
|
|
|
self.memory.write_int(dest, 0, dest_size)?;
|
2016-05-25 00:37:52 -06:00
|
|
|
}
|
|
|
|
} else {
|
2016-09-06 16:16:49 +02:00
|
|
|
bug!("tried to assign {:?} to Layout::RawNullablePointer", kind);
|
2016-05-25 00:37:52 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-26 22:58:01 -08:00
|
|
|
CEnum { .. } => {
|
2016-05-08 19:29:00 -06:00
|
|
|
assert_eq!(operands.len(), 0);
|
2016-09-06 16:04:51 +02:00
|
|
|
if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind {
|
2017-03-02 13:11:33 +01:00
|
|
|
let n = adt_def.discriminants(self.tcx)
|
|
|
|
.nth(variant)
|
|
|
|
.expect("broken mir: Adt variant index invalid")
|
|
|
|
.to_u128_unchecked();
|
2016-12-15 23:40:45 -08:00
|
|
|
self.write_primval(dest, PrimVal::Bytes(n), dest_ty)?;
|
2016-05-08 19:29:00 -06:00
|
|
|
} else {
|
2016-09-06 16:16:49 +02:00
|
|
|
bug!("tried to assign {:?} to Layout::CEnum", kind);
|
2016-05-08 19:29:00 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-13 11:58:42 +01:00
|
|
|
Vector { count, .. } => {
|
2016-11-15 15:23:19 +01:00
|
|
|
debug_assert_eq!(count, operands.len() as u64);
|
2017-02-13 11:58:42 +01:00
|
|
|
self.assign_fields(dest, dest_ty, operands)?;
|
2016-11-15 15:23:19 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 23:25:47 -08:00
|
|
|
UntaggedUnion { .. } => {
|
|
|
|
assert_eq!(operands.len(), 1);
|
|
|
|
let operand = &operands[0];
|
|
|
|
let value = self.eval_operand(operand)?;
|
|
|
|
let value_ty = self.operand_ty(operand);
|
|
|
|
self.write_value(value, dest, value_ty)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => {
|
|
|
|
return Err(EvalError::Unimplemented(format!(
|
|
|
|
"can't handle destination layout {:?} when assigning {:?}",
|
|
|
|
dest_layout,
|
|
|
|
kind
|
|
|
|
)));
|
|
|
|
}
|
2016-03-12 22:15:59 -06:00
|
|
|
}
|
2015-11-12 15:50:58 -06:00
|
|
|
}
|
2015-11-12 17:24:43 -06:00
|
|
|
|
2016-03-21 03:34:24 -06:00
|
|
|
Repeat(ref operand, _) => {
|
2016-09-19 02:19:31 -06:00
|
|
|
let (elem_ty, length) = match dest_ty.sty {
|
2016-11-18 12:55:14 +01:00
|
|
|
ty::TyArray(elem_ty, n) => (elem_ty, n as u64),
|
2016-09-06 16:16:49 +02:00
|
|
|
_ => bug!("tried to assign array-repeat to non-array type {:?}", dest_ty),
|
2016-04-23 00:03:59 -06:00
|
|
|
};
|
2016-11-18 12:55:14 +01:00
|
|
|
self.inc_step_counter_and_check_limit(length)?;
|
2016-12-18 20:59:01 -08:00
|
|
|
let elem_size = self.type_size(elem_ty)?
|
|
|
|
.expect("repeat element type must be sized");
|
2016-09-19 02:19:31 -06:00
|
|
|
let value = self.eval_operand(operand)?;
|
2016-10-14 03:31:45 -06:00
|
|
|
|
|
|
|
// FIXME(solson)
|
2016-10-15 19:48:30 -06:00
|
|
|
let dest = self.force_allocation(dest)?.to_ptr();
|
2016-10-14 03:31:45 -06:00
|
|
|
|
2016-04-23 00:03:59 -06:00
|
|
|
for i in 0..length {
|
2016-11-18 12:55:14 +01:00
|
|
|
let elem_dest = dest.offset(i * elem_size);
|
2016-10-14 03:31:45 -06:00
|
|
|
self.write_value_to_ptr(value, elem_dest, elem_ty)?;
|
2016-03-21 03:34:24 -06:00
|
|
|
}
|
|
|
|
}
|
2016-03-21 03:19:48 -06:00
|
|
|
|
2016-03-20 21:30:31 -06:00
|
|
|
Len(ref lvalue) => {
|
2016-05-09 18:52:44 -06:00
|
|
|
let src = self.eval_lvalue(lvalue)?;
|
2016-03-20 21:30:31 -06:00
|
|
|
let ty = self.lvalue_ty(lvalue);
|
2016-09-28 18:22:09 +02:00
|
|
|
let (_, len) = src.elem_ty_and_len(ty);
|
2017-01-12 08:28:42 +01:00
|
|
|
self.write_primval(dest, PrimVal::from_u128(len as u128), dest_ty)?;
|
2016-03-20 21:30:31 -06:00
|
|
|
}
|
|
|
|
|
2016-03-13 14:36:25 -06:00
|
|
|
Ref(_, _, ref lvalue) => {
|
2016-10-16 02:12:46 -06:00
|
|
|
let src = self.eval_lvalue(lvalue)?;
|
|
|
|
let (raw_ptr, extra) = self.force_allocation(src)?.to_ptr_and_extra();
|
2016-12-15 23:55:00 -08:00
|
|
|
let ptr = PrimVal::Ptr(raw_ptr);
|
2016-10-14 22:10:06 -06:00
|
|
|
|
2016-10-16 02:12:46 -06:00
|
|
|
let val = match extra {
|
|
|
|
LvalueExtra::None => Value::ByVal(ptr),
|
2017-01-12 08:28:42 +01:00
|
|
|
LvalueExtra::Length(len) => Value::ByValPair(ptr, PrimVal::from_u128(len as u128)),
|
2016-12-15 23:55:00 -08:00
|
|
|
LvalueExtra::Vtable(vtable) => Value::ByValPair(ptr, PrimVal::Ptr(vtable)),
|
2016-09-27 10:14:53 +02:00
|
|
|
LvalueExtra::DowncastVariant(..) =>
|
|
|
|
bug!("attempted to take a reference to an enum downcast lvalue"),
|
2016-10-16 02:12:46 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
self.write_value(val, dest, dest_ty)?;
|
2016-03-13 14:36:25 -06:00
|
|
|
}
|
2015-12-28 22:24:05 -06:00
|
|
|
|
2016-03-14 22:05:50 -06:00
|
|
|
Box(ty) => {
|
2016-10-16 00:12:27 -06:00
|
|
|
let ptr = self.alloc_ptr(ty)?;
|
2016-12-15 23:55:00 -08:00
|
|
|
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
|
2016-03-14 22:05:50 -06:00
|
|
|
}
|
|
|
|
|
2016-09-27 18:01:33 +02:00
|
|
|
Cast(kind, ref operand, cast_ty) => {
|
|
|
|
debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest_ty);
|
2016-11-03 10:38:08 +01:00
|
|
|
use rustc::mir::CastKind::*;
|
2016-03-16 23:28:49 -06:00
|
|
|
match kind {
|
|
|
|
Unsize => {
|
2016-09-23 10:27:14 +02:00
|
|
|
let src = self.eval_operand(operand)?;
|
2016-06-08 13:43:34 +02:00
|
|
|
let src_ty = self.operand_ty(operand);
|
2016-09-27 18:01:33 +02:00
|
|
|
self.unsize_into(src, src_ty, dest, dest_ty)?;
|
2016-03-16 23:28:49 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
Misc => {
|
2016-09-23 10:27:14 +02:00
|
|
|
let src = self.eval_operand(operand)?;
|
2016-06-13 11:24:01 +02:00
|
|
|
let src_ty = self.operand_ty(operand);
|
2016-09-08 10:26:33 +02:00
|
|
|
if self.type_is_fat_ptr(src_ty) {
|
2016-09-23 10:27:14 +02:00
|
|
|
trace!("misc cast: {:?}", src);
|
|
|
|
match (src, self.type_is_fat_ptr(dest_ty)) {
|
2016-10-21 13:56:38 +02:00
|
|
|
(Value::ByRef(_), _) |
|
|
|
|
(Value::ByValPair(..), true) => {
|
|
|
|
self.write_value(src, dest, dest_ty)?;
|
2016-09-23 10:27:14 +02:00
|
|
|
},
|
2016-09-26 17:49:30 +02:00
|
|
|
(Value::ByValPair(data, _), false) => {
|
2016-10-21 13:56:38 +02:00
|
|
|
self.write_value(Value::ByVal(data), dest, dest_ty)?;
|
2016-09-23 10:27:14 +02:00
|
|
|
},
|
|
|
|
(Value::ByVal(_), _) => bug!("expected fat ptr"),
|
2016-09-07 18:34:59 +02:00
|
|
|
}
|
2016-09-08 10:26:33 +02:00
|
|
|
} else {
|
2016-09-23 10:27:14 +02:00
|
|
|
let src_val = self.value_to_primval(src, src_ty)?;
|
2016-11-26 22:58:01 -08:00
|
|
|
let dest_val = self.cast_primval(src_val, src_ty, dest_ty)?;
|
2016-10-21 13:56:38 +02:00
|
|
|
self.write_value(Value::ByVal(dest_val), dest, dest_ty)?;
|
2016-06-13 11:24:01 +02:00
|
|
|
}
|
2016-03-16 23:28:49 -06:00
|
|
|
}
|
|
|
|
|
2016-06-08 13:43:34 +02:00
|
|
|
ReifyFnPointer => match self.operand_ty(operand).sty {
|
2017-03-02 13:11:33 +01:00
|
|
|
ty::TyFnDef(def_id, substs, sig) => {
|
|
|
|
let fn_ptr = self.memory.create_fn_ptr(def_id, substs, sig);
|
2016-12-15 23:55:00 -08:00
|
|
|
self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?;
|
2016-06-08 13:43:34 +02:00
|
|
|
},
|
2016-09-06 16:16:49 +02:00
|
|
|
ref other => bug!("reify fn pointer on {:?}", other),
|
2016-06-08 13:43:34 +02:00
|
|
|
},
|
|
|
|
|
2016-06-17 16:49:06 +02:00
|
|
|
UnsafeFnPointer => match dest_ty.sty {
|
2017-02-28 12:35:00 +01:00
|
|
|
ty::TyFnPtr(_) => {
|
2016-09-23 10:27:14 +02:00
|
|
|
let src = self.eval_operand(operand)?;
|
2017-02-28 12:35:00 +01:00
|
|
|
self.write_value(src, dest, dest_ty)?;
|
2016-06-17 16:49:06 +02:00
|
|
|
},
|
2016-09-06 16:16:49 +02:00
|
|
|
ref other => bug!("fn to unsafe fn cast on {:?}", other),
|
2016-06-17 16:49:06 +02:00
|
|
|
},
|
2017-02-28 12:35:00 +01:00
|
|
|
|
|
|
|
ClosureFnPointer => match self.operand_ty(operand).sty {
|
|
|
|
ty::TyClosure(def_id, substs) => {
|
2017-03-02 13:11:33 +01:00
|
|
|
let fn_ty = self.tcx.closure_type(def_id);
|
|
|
|
let fn_ptr = self.memory.create_fn_ptr_from_noncapture_closure(def_id, substs, fn_ty);
|
2017-02-28 12:35:00 +01:00
|
|
|
self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?;
|
|
|
|
},
|
|
|
|
ref other => bug!("reify fn pointer on {:?}", other),
|
|
|
|
},
|
2016-03-16 23:28:49 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-24 10:39:55 +01:00
|
|
|
Discriminant(ref lvalue) => {
|
|
|
|
let lval = self.eval_lvalue(lvalue)?;
|
|
|
|
let ty = self.lvalue_ty(lvalue);
|
|
|
|
let ptr = self.force_allocation(lval)?.to_ptr();
|
|
|
|
let discr_val = self.read_discriminant_value(ptr, ty)?;
|
|
|
|
if let ty::TyAdt(adt_def, _) = ty.sty {
|
2017-03-02 13:11:33 +01:00
|
|
|
if adt_def.discriminants(self.tcx).all(|v| discr_val != v.to_u128_unchecked()) {
|
2017-02-24 10:39:55 +01:00
|
|
|
return Err(EvalError::InvalidDiscriminant);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bug!("rustc only generates Rvalue::Discriminant for enums");
|
|
|
|
}
|
|
|
|
self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
|
|
|
|
},
|
2015-11-12 15:50:58 -06:00
|
|
|
}
|
2016-03-20 23:09:27 -06:00
|
|
|
|
2016-10-20 04:42:19 -06:00
|
|
|
if log_enabled!(::log::LogLevel::Trace) {
|
|
|
|
self.dump_local(dest);
|
|
|
|
}
|
|
|
|
|
2016-03-20 23:09:27 -06:00
|
|
|
Ok(())
|
2015-11-12 15:50:58 -06:00
|
|
|
}
|
|
|
|
|
2016-09-07 18:34:59 +02:00
|
|
|
fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
|
|
|
|
match ty.sty {
|
2017-02-03 15:47:23 +01:00
|
|
|
ty::TyRawPtr(ref tam) |
|
|
|
|
ty::TyRef(_, ref tam) => !self.type_is_sized(tam.ty),
|
|
|
|
ty::TyAdt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()),
|
2016-09-07 18:34:59 +02:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn nonnull_offset_and_ty(
|
|
|
|
&self,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
nndiscr: u64,
|
|
|
|
discrfield: &[u32],
|
|
|
|
) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
|
2016-11-18 12:55:14 +01:00
|
|
|
// Skip the constant 0 at the start meant for LLVM GEP and the outer non-null variant
|
|
|
|
let path = discrfield.iter().skip(2).map(|&i| i as usize);
|
2016-05-25 00:37:52 -06:00
|
|
|
|
|
|
|
// Handle the field index for the outer non-null variant.
|
2017-01-28 15:46:46 +01:00
|
|
|
let (inner_offset, inner_ty) = match ty.sty {
|
2016-09-10 20:59:23 -06:00
|
|
|
ty::TyAdt(adt_def, substs) => {
|
2016-05-25 00:37:52 -06:00
|
|
|
let variant = &adt_def.variants[nndiscr as usize];
|
2016-11-18 12:55:14 +01:00
|
|
|
let index = discrfield[1];
|
|
|
|
let field = &variant.fields[index as usize];
|
2017-01-28 15:46:46 +01:00
|
|
|
(self.get_field_offset(ty, index as usize)?, field.ty(self.tcx, substs))
|
2016-05-25 00:37:52 -06:00
|
|
|
}
|
2016-09-06 16:16:49 +02:00
|
|
|
_ => bug!("non-enum for StructWrappedNullablePointer: {}", ty),
|
2016-05-25 00:37:52 -06:00
|
|
|
};
|
|
|
|
|
2017-01-28 15:46:46 +01:00
|
|
|
self.field_path_offset_and_ty(inner_offset, inner_ty, path)
|
2016-05-25 00:37:52 -06:00
|
|
|
}
|
|
|
|
|
2017-01-28 15:46:46 +01:00
|
|
|
fn field_path_offset_and_ty<I: Iterator<Item = usize>>(
|
|
|
|
&self,
|
|
|
|
mut offset: Size,
|
|
|
|
mut ty: Ty<'tcx>,
|
|
|
|
path: I,
|
|
|
|
) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
|
2016-05-25 00:37:52 -06:00
|
|
|
// Skip the initial 0 intended for LLVM GEP.
|
|
|
|
for field_index in path {
|
2016-05-30 15:27:52 +02:00
|
|
|
let field_offset = self.get_field_offset(ty, field_index)?;
|
2016-11-17 14:48:34 +01:00
|
|
|
trace!("field_path_offset_and_ty: {}, {}, {:?}, {:?}", field_index, ty, field_offset, offset);
|
2016-05-30 15:27:52 +02:00
|
|
|
ty = self.get_field_ty(ty, field_index)?;
|
2016-05-25 00:37:52 -06:00
|
|
|
offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap();
|
|
|
|
}
|
|
|
|
|
2016-11-11 13:10:47 +01:00
|
|
|
Ok((offset, ty))
|
2016-05-25 00:37:52 -06:00
|
|
|
}
|
2017-02-03 15:47:23 +01:00
|
|
|
fn get_fat_field(&self, pointee_ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
|
|
|
|
match (field_index, &self.tcx.struct_tail(pointee_ty).sty) {
|
|
|
|
(1, &ty::TyStr) |
|
|
|
|
(1, &ty::TySlice(_)) => Ok(self.tcx.types.usize),
|
|
|
|
(1, &ty::TyDynamic(..)) |
|
|
|
|
(0, _) => Ok(self.tcx.mk_imm_ptr(self.tcx.types.u8)),
|
|
|
|
_ => bug!("invalid fat pointee type: {}", pointee_ty),
|
|
|
|
}
|
|
|
|
}
|
2016-05-25 00:37:52 -06:00
|
|
|
|
2017-01-11 10:04:17 +01:00
|
|
|
pub fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
|
2016-05-25 00:37:52 -06:00
|
|
|
match ty.sty {
|
2017-02-03 15:47:23 +01:00
|
|
|
ty::TyAdt(adt_def, _) if adt_def.is_box() => self.get_fat_field(ty.boxed_ty(), field_index),
|
2016-09-10 20:59:23 -06:00
|
|
|
ty::TyAdt(adt_def, substs) => {
|
2016-05-30 15:27:52 +02:00
|
|
|
Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs))
|
2016-05-25 00:37:52 -06:00
|
|
|
}
|
|
|
|
|
2017-02-07 06:01:03 -08:00
|
|
|
ty::TyTuple(fields, _) => Ok(fields[field_index]),
|
2016-09-28 18:22:53 +02:00
|
|
|
|
2017-02-03 15:47:23 +01:00
|
|
|
ty::TyRef(_, ref tam) |
|
|
|
|
ty::TyRawPtr(ref tam) => self.get_fat_field(tam.ty, field_index),
|
2016-09-28 18:22:53 +02:00
|
|
|
_ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, {:?}", ty, ty.sty))),
|
2016-05-25 00:37:52 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-14 10:34:54 +02:00
|
|
|
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Size> {
|
2016-11-17 17:23:40 +01:00
|
|
|
let layout = self.type_layout(ty)?;
|
2016-05-25 00:37:52 -06:00
|
|
|
|
|
|
|
use rustc::ty::layout::Layout::*;
|
|
|
|
match *layout {
|
2016-09-27 18:01:33 +02:00
|
|
|
Univariant { ref variant, .. } => {
|
2016-10-03 20:45:50 -06:00
|
|
|
Ok(variant.offsets[field_index])
|
2016-05-25 00:37:52 -06:00
|
|
|
}
|
|
|
|
FatPointer { .. } => {
|
2016-11-18 12:55:14 +01:00
|
|
|
let bytes = field_index as u64 * self.memory.pointer_size();
|
|
|
|
Ok(Size::from_bytes(bytes))
|
2016-05-25 00:37:52 -06:00
|
|
|
}
|
2017-01-28 15:46:46 +01:00
|
|
|
StructWrappedNullablePointer { ref nonnull, .. } => {
|
|
|
|
Ok(nonnull.offsets[field_index])
|
|
|
|
}
|
2016-10-16 02:12:46 -06:00
|
|
|
_ => {
|
|
|
|
let msg = format!("can't handle type: {:?}, with layout: {:?}", ty, layout);
|
|
|
|
Err(EvalError::Unimplemented(msg))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_field_count(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, usize> {
|
2016-11-17 17:23:40 +01:00
|
|
|
let layout = self.type_layout(ty)?;
|
2016-10-16 02:12:46 -06:00
|
|
|
|
|
|
|
use rustc::ty::layout::Layout::*;
|
|
|
|
match *layout {
|
|
|
|
Univariant { ref variant, .. } => Ok(variant.offsets.len()),
|
|
|
|
FatPointer { .. } => Ok(2),
|
2017-01-28 15:46:46 +01:00
|
|
|
StructWrappedNullablePointer { ref nonnull, .. } => Ok(nonnull.offsets.len()),
|
2016-10-16 02:12:46 -06:00
|
|
|
_ => {
|
|
|
|
let msg = format!("can't handle type: {:?}, with layout: {:?}", ty, layout);
|
|
|
|
Err(EvalError::Unimplemented(msg))
|
|
|
|
}
|
2016-05-25 00:37:52 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn eval_operand_to_primval(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, PrimVal> {
|
2016-09-19 02:19:31 -06:00
|
|
|
let value = self.eval_operand(op)?;
|
|
|
|
let ty = self.operand_ty(op);
|
|
|
|
self.value_to_primval(value, ty)
|
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, Value> {
|
2016-11-03 10:38:08 +01:00
|
|
|
use rustc::mir::Operand::*;
|
2015-11-12 15:50:58 -06:00
|
|
|
match *op {
|
2016-10-15 23:59:01 -06:00
|
|
|
Consume(ref lvalue) => self.eval_and_read_lvalue(lvalue),
|
2016-09-19 02:19:31 -06:00
|
|
|
|
2016-06-09 11:16:09 +02:00
|
|
|
Constant(mir::Constant { ref literal, ty, .. }) => {
|
2016-11-03 10:38:08 +01:00
|
|
|
use rustc::mir::Literal;
|
2016-09-19 02:19:31 -06:00
|
|
|
let value = match *literal {
|
2016-09-26 17:49:30 +02:00
|
|
|
Literal::Value { ref value } => self.const_to_value(value)?,
|
2016-09-19 02:19:31 -06:00
|
|
|
|
|
|
|
Literal::Item { def_id, substs } => {
|
2016-06-09 11:27:02 +02:00
|
|
|
if let ty::TyFnDef(..) = ty.sty {
|
2016-06-08 13:43:34 +02:00
|
|
|
// function items are zero sized
|
2016-09-19 03:35:35 -06:00
|
|
|
Value::ByRef(self.memory.allocate(0, 0)?)
|
2016-06-03 15:48:56 +02:00
|
|
|
} else {
|
2017-02-10 03:12:33 -08:00
|
|
|
let (def_id, substs) = self.resolve_associated_const(def_id, substs);
|
2017-01-16 18:45:30 -08:00
|
|
|
let cid = GlobalId { def_id, substs, promoted: None };
|
2017-02-10 11:29:07 +01:00
|
|
|
self.globals.get(&cid).expect("static/const not cached").value
|
2016-06-03 15:48:56 +02:00
|
|
|
}
|
2016-09-19 02:19:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
Literal::Promoted { index } => {
|
2016-10-21 11:39:39 +02:00
|
|
|
let cid = GlobalId {
|
2016-06-03 17:41:36 +02:00
|
|
|
def_id: self.frame().def_id,
|
|
|
|
substs: self.substs(),
|
2016-10-21 11:54:38 +02:00
|
|
|
promoted: Some(index),
|
2016-06-03 17:41:36 +02:00
|
|
|
};
|
2017-02-10 11:29:07 +01:00
|
|
|
self.globals.get(&cid).expect("promoted not cached").value
|
2016-09-19 02:19:31 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(value)
|
2015-11-12 15:50:58 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-11-12 17:44:29 -06:00
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'tcx> {
|
2016-08-27 01:44:46 -06:00
|
|
|
self.monomorphize(operand.ty(&self.mir(), self.tcx), self.substs())
|
2016-04-07 03:02:02 -06:00
|
|
|
}
|
|
|
|
|
2017-02-04 13:09:10 -08:00
|
|
|
fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx> {
|
2016-11-17 17:23:40 +01:00
|
|
|
let size = self.type_size(ty)?.expect("cannot copy from an unsized type");
|
|
|
|
let align = self.type_align(ty)?;
|
2016-07-22 16:35:39 +02:00
|
|
|
self.memory.copy(src, dest, size, align)?;
|
2016-04-07 05:56:07 -06:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn force_allocation(
|
|
|
|
&mut self,
|
|
|
|
lvalue: Lvalue<'tcx>,
|
|
|
|
) -> EvalResult<'tcx, Lvalue<'tcx>> {
|
2016-10-15 19:48:30 -06:00
|
|
|
let new_lvalue = match lvalue {
|
2017-02-10 16:14:59 +01:00
|
|
|
Lvalue::Local { frame, local, field } => {
|
|
|
|
// -1 since we don't store the return value
|
|
|
|
match self.stack[frame].locals[local.index() - 1] {
|
|
|
|
Value::ByRef(ptr) => {
|
|
|
|
assert!(field.is_none());
|
|
|
|
Lvalue::from_ptr(ptr)
|
|
|
|
},
|
2016-12-18 20:59:01 -08:00
|
|
|
val => {
|
2016-10-15 19:48:30 -06:00
|
|
|
let ty = self.stack[frame].mir.local_decls[local].ty;
|
2016-11-26 22:58:01 -08:00
|
|
|
let ty = self.monomorphize(ty, self.stack[frame].substs);
|
2016-10-15 19:48:30 -06:00
|
|
|
let substs = self.stack[frame].substs;
|
2016-10-16 00:12:11 -06:00
|
|
|
let ptr = self.alloc_ptr_with_substs(ty, substs)?;
|
2017-02-10 16:14:59 +01:00
|
|
|
self.stack[frame].locals[local.index() - 1] = Value::ByRef(ptr);
|
2016-12-18 20:59:01 -08:00
|
|
|
self.write_value_to_ptr(val, ptr, ty)?;
|
2017-02-10 16:14:59 +01:00
|
|
|
let lval = Lvalue::from_ptr(ptr);
|
|
|
|
if let Some((field, field_ty)) = field {
|
|
|
|
self.lvalue_field(lval, field, ty, field_ty)?
|
|
|
|
} else {
|
|
|
|
lval
|
|
|
|
}
|
2016-10-15 19:48:30 -06:00
|
|
|
}
|
2016-10-21 10:32:27 +02:00
|
|
|
}
|
2016-10-15 19:48:30 -06:00
|
|
|
}
|
|
|
|
Lvalue::Ptr { .. } => lvalue,
|
2016-10-21 11:48:56 +02:00
|
|
|
Lvalue::Global(cid) => {
|
|
|
|
let global_val = *self.globals.get(&cid).expect("global not cached");
|
2016-12-18 20:59:01 -08:00
|
|
|
match global_val.value {
|
|
|
|
Value::ByRef(ptr) => Lvalue::from_ptr(ptr),
|
2016-10-21 10:32:27 +02:00
|
|
|
_ => {
|
2016-10-21 11:48:56 +02:00
|
|
|
let ptr = self.alloc_ptr_with_substs(global_val.ty, cid.substs)?;
|
2017-02-08 16:27:28 +01:00
|
|
|
self.memory.mark_static(ptr.alloc_id);
|
2016-12-18 20:59:01 -08:00
|
|
|
self.write_value_to_ptr(global_val.value, ptr, global_val.ty)?;
|
2017-02-08 15:32:49 +01:00
|
|
|
// see comment on `initialized` field
|
|
|
|
if global_val.initialized {
|
2017-02-08 16:27:28 +01:00
|
|
|
self.memory.mark_static_initalized(ptr.alloc_id, global_val.mutable)?;
|
2017-02-08 15:32:49 +01:00
|
|
|
}
|
2016-10-21 11:39:39 +02:00
|
|
|
let lval = self.globals.get_mut(&cid).expect("already checked");
|
|
|
|
*lval = Global {
|
2016-12-18 20:59:01 -08:00
|
|
|
value: Value::ByRef(ptr),
|
2016-10-21 11:48:56 +02:00
|
|
|
.. global_val
|
2016-10-21 10:32:27 +02:00
|
|
|
};
|
|
|
|
Lvalue::from_ptr(ptr)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2016-10-15 19:48:30 -06:00
|
|
|
};
|
|
|
|
Ok(new_lvalue)
|
|
|
|
}
|
|
|
|
|
2016-11-04 15:49:51 +01:00
|
|
|
/// ensures this Value is not a ByRef
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn follow_by_ref_value(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
|
2016-09-19 02:19:31 -06:00
|
|
|
match value {
|
2016-11-04 15:49:51 +01:00
|
|
|
Value::ByRef(ptr) => self.read_value(ptr, ty),
|
|
|
|
other => Ok(other),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn value_to_primval(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
|
2016-11-04 15:49:51 +01:00
|
|
|
match self.follow_by_ref_value(value, ty)? {
|
|
|
|
Value::ByRef(_) => bug!("follow_by_ref_value can't result in `ByRef`"),
|
2016-09-19 02:19:31 -06:00
|
|
|
|
2016-10-15 19:48:30 -06:00
|
|
|
Value::ByVal(primval) => {
|
2016-11-26 23:42:17 -08:00
|
|
|
self.ensure_valid_value(primval, ty)?;
|
|
|
|
Ok(primval)
|
2016-10-15 19:48:30 -06:00
|
|
|
}
|
|
|
|
|
2016-09-26 17:49:30 +02:00
|
|
|
Value::ByValPair(..) => bug!("value_to_primval can't work with fat pointers"),
|
2016-09-19 02:19:31 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn write_primval(
|
2016-10-14 03:31:45 -06:00
|
|
|
&mut self,
|
2016-10-21 10:29:56 +02:00
|
|
|
dest: Lvalue<'tcx>,
|
2016-10-14 03:31:45 -06:00
|
|
|
val: PrimVal,
|
2016-11-26 22:58:01 -08:00
|
|
|
dest_ty: Ty<'tcx>,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2017-02-14 16:56:21 +01:00
|
|
|
self.write_value(Value::ByVal(val), dest, dest_ty)
|
2016-10-14 03:31:45 -06:00
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn write_value(
|
2016-10-14 03:31:45 -06:00
|
|
|
&mut self,
|
Fix write_value of ByVal into a ByRef.
Previously, you could perform the following, if you assume we could make
`Cell<i32>` into a primitive. (Alternately, you could achieve this with
unsafe code):
x = Cell::new(12);
y = &x;
// Miri locals array:
// x = ByRef(alloc123);
// y = ByVal(Ptr(alloc123));
//
// Miri allocations:
// alloc123: [12, 0, 0, 0]
x.set(42);
// Miri locals array:
// x = ByVal(I32(42));
// y = ByVal(Ptr(alloc123));
//
// Miri allocations:
// alloc123: [12, 0, 0, 0]
Notice how `y` still refers to the allocation that used to represent
`x`. But now `x` was changed to `42` and `y` is still looking at memory
containing `12`.
Now, instead, we keep `x` as a `ByRef` and write the `42` constant into
it.
Unit test to follow in the next commit.
2016-10-18 21:02:37 -06:00
|
|
|
src_val: Value,
|
2016-10-21 10:29:56 +02:00
|
|
|
dest: Lvalue<'tcx>,
|
2016-10-14 03:31:45 -06:00
|
|
|
dest_ty: Ty<'tcx>,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2016-10-15 19:48:30 -06:00
|
|
|
match dest {
|
2016-10-21 11:48:56 +02:00
|
|
|
Lvalue::Global(cid) => {
|
|
|
|
let dest = *self.globals.get_mut(&cid).expect("global should be cached");
|
2016-10-21 11:51:24 +02:00
|
|
|
if !dest.mutable {
|
|
|
|
return Err(EvalError::ModifiedConstantMemory);
|
|
|
|
}
|
2016-12-18 20:59:01 -08:00
|
|
|
let write_dest = |this: &mut Self, val| {
|
|
|
|
*this.globals.get_mut(&cid).expect("already checked") = Global {
|
|
|
|
value: val,
|
|
|
|
..dest
|
|
|
|
}
|
|
|
|
};
|
|
|
|
self.write_value_possibly_by_val(src_val, write_dest, dest.value, dest_ty)
|
2016-10-21 10:32:27 +02:00
|
|
|
},
|
|
|
|
|
2016-10-15 19:48:30 -06:00
|
|
|
Lvalue::Ptr { ptr, extra } => {
|
|
|
|
assert_eq!(extra, LvalueExtra::None);
|
2016-10-21 10:32:27 +02:00
|
|
|
self.write_value_to_ptr(src_val, ptr, dest_ty)
|
2016-10-15 19:48:30 -06:00
|
|
|
}
|
Fix write_value of ByVal into a ByRef.
Previously, you could perform the following, if you assume we could make
`Cell<i32>` into a primitive. (Alternately, you could achieve this with
unsafe code):
x = Cell::new(12);
y = &x;
// Miri locals array:
// x = ByRef(alloc123);
// y = ByVal(Ptr(alloc123));
//
// Miri allocations:
// alloc123: [12, 0, 0, 0]
x.set(42);
// Miri locals array:
// x = ByVal(I32(42));
// y = ByVal(Ptr(alloc123));
//
// Miri allocations:
// alloc123: [12, 0, 0, 0]
Notice how `y` still refers to the allocation that used to represent
`x`. But now `x` was changed to `42` and `y` is still looking at memory
containing `12`.
Now, instead, we keep `x` as a `ByRef` and write the `42` constant into
it.
Unit test to follow in the next commit.
2016-10-18 21:02:37 -06:00
|
|
|
|
2017-02-10 16:14:59 +01:00
|
|
|
Lvalue::Local { frame, local, field } => {
|
|
|
|
let dest = self.stack[frame].get_local(local, field.map(|(i, _)| i));
|
2016-10-21 11:24:10 +02:00
|
|
|
self.write_value_possibly_by_val(
|
2016-10-21 10:32:27 +02:00
|
|
|
src_val,
|
2017-02-10 16:14:59 +01:00
|
|
|
|this, val| this.stack[frame].set_local(local, field.map(|(i, _)| i), val),
|
2016-10-21 10:32:27 +02:00
|
|
|
dest,
|
|
|
|
dest_ty,
|
|
|
|
)
|
2016-10-15 19:48:30 -06:00
|
|
|
}
|
|
|
|
}
|
2016-10-21 10:32:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// The cases here can be a bit subtle. Read carefully!
|
2016-10-21 11:24:10 +02:00
|
|
|
fn write_value_possibly_by_val<F: FnOnce(&mut Self, Value)>(
|
2016-10-21 10:32:27 +02:00
|
|
|
&mut self,
|
|
|
|
src_val: Value,
|
|
|
|
write_dest: F,
|
2016-12-18 20:59:01 -08:00
|
|
|
old_dest_val: Value,
|
2016-10-21 10:32:27 +02:00
|
|
|
dest_ty: Ty<'tcx>,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2016-12-18 20:59:01 -08:00
|
|
|
if let Value::ByRef(dest_ptr) = old_dest_val {
|
2016-10-21 12:03:34 +02:00
|
|
|
// If the value is already `ByRef` (that is, backed by an `Allocation`),
|
2016-10-21 10:32:27 +02:00
|
|
|
// then we must write the new value into this allocation, because there may be
|
|
|
|
// other pointers into the allocation. These other pointers are logically
|
|
|
|
// pointers into the local variable, and must be able to observe the change.
|
|
|
|
//
|
|
|
|
// Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we
|
2016-10-21 12:03:34 +02:00
|
|
|
// knew for certain that there were no outstanding pointers to this allocation.
|
2016-10-21 10:32:27 +02:00
|
|
|
self.write_value_to_ptr(src_val, dest_ptr, dest_ty)?;
|
|
|
|
|
|
|
|
} else if let Value::ByRef(src_ptr) = src_val {
|
2016-10-21 12:03:34 +02:00
|
|
|
// If the value is not `ByRef`, then we know there are no pointers to it
|
2016-10-21 10:32:27 +02:00
|
|
|
// and we can simply overwrite the `Value` in the locals array directly.
|
|
|
|
//
|
|
|
|
// In this specific case, where the source value is `ByRef`, we must duplicate
|
|
|
|
// the allocation, because this is a by-value operation. It would be incorrect
|
|
|
|
// if they referred to the same allocation, since then a change to one would
|
|
|
|
// implicitly change the other.
|
|
|
|
//
|
2016-11-28 20:22:21 -08:00
|
|
|
// It is a valid optimization to attempt reading a primitive value out of the
|
|
|
|
// source and write that into the destination without making an allocation, so
|
|
|
|
// we do so here.
|
|
|
|
if let Ok(Some(src_val)) = self.try_read_value(src_ptr, dest_ty) {
|
|
|
|
write_dest(self, src_val);
|
|
|
|
} else {
|
|
|
|
let dest_ptr = self.alloc_ptr(dest_ty)?;
|
|
|
|
self.copy(src_ptr, dest_ptr, dest_ty)?;
|
|
|
|
write_dest(self, Value::ByRef(dest_ptr));
|
|
|
|
}
|
2016-10-21 10:32:27 +02:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// Finally, we have the simple case where neither source nor destination are
|
2016-10-21 12:03:34 +02:00
|
|
|
// `ByRef`. We may simply copy the source value over the the destintion.
|
2016-10-21 10:32:27 +02:00
|
|
|
write_dest(self, src_val);
|
|
|
|
}
|
2016-10-15 19:48:30 -06:00
|
|
|
Ok(())
|
2016-10-14 03:31:45 -06:00
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn write_value_to_ptr(
|
2016-09-19 03:35:35 -06:00
|
|
|
&mut self,
|
|
|
|
value: Value,
|
|
|
|
dest: Pointer,
|
2016-10-14 03:31:45 -06:00
|
|
|
dest_ty: Ty<'tcx>,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2016-09-19 02:19:31 -06:00
|
|
|
match value {
|
2016-10-14 03:31:45 -06:00
|
|
|
Value::ByRef(ptr) => self.copy(ptr, dest, dest_ty),
|
2016-11-26 22:58:01 -08:00
|
|
|
Value::ByVal(primval) => {
|
2016-12-18 20:59:01 -08:00
|
|
|
let size = self.type_size(dest_ty)?.expect("dest type must be sized");
|
|
|
|
self.memory.write_primval(dest, primval, size)
|
2016-11-26 22:58:01 -08:00
|
|
|
}
|
2016-10-16 15:31:02 -06:00
|
|
|
Value::ByValPair(a, b) => self.write_pair_to_ptr(a, b, dest, dest_ty),
|
2016-09-26 17:49:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn write_pair_to_ptr(
|
2016-10-16 15:31:02 -06:00
|
|
|
&mut self,
|
|
|
|
a: PrimVal,
|
|
|
|
b: PrimVal,
|
|
|
|
ptr: Pointer,
|
|
|
|
ty: Ty<'tcx>
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2016-10-16 15:31:02 -06:00
|
|
|
assert_eq!(self.get_field_count(ty)?, 2);
|
2016-11-18 12:55:14 +01:00
|
|
|
let field_0 = self.get_field_offset(ty, 0)?.bytes();
|
|
|
|
let field_1 = self.get_field_offset(ty, 1)?.bytes();
|
2016-11-26 22:58:01 -08:00
|
|
|
let field_0_ty = self.get_field_ty(ty, 0)?;
|
|
|
|
let field_1_ty = self.get_field_ty(ty, 1)?;
|
2016-12-18 20:59:01 -08:00
|
|
|
let field_0_size = self.type_size(field_0_ty)?.expect("pair element type must be sized");
|
|
|
|
let field_1_size = self.type_size(field_1_ty)?.expect("pair element type must be sized");
|
|
|
|
self.memory.write_primval(ptr.offset(field_0), a, field_0_size)?;
|
|
|
|
self.memory.write_primval(ptr.offset(field_1), b, field_1_size)?;
|
2016-10-16 15:31:02 -06:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2017-01-11 10:04:17 +01:00
|
|
|
pub fn ty_to_primval_kind(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimValKind> {
|
2016-10-21 03:17:53 -06:00
|
|
|
use syntax::ast::FloatTy;
|
|
|
|
|
|
|
|
let kind = match ty.sty {
|
|
|
|
ty::TyBool => PrimValKind::Bool,
|
|
|
|
ty::TyChar => PrimValKind::Char,
|
|
|
|
|
|
|
|
ty::TyInt(int_ty) => {
|
|
|
|
use syntax::ast::IntTy::*;
|
|
|
|
let size = match int_ty {
|
|
|
|
I8 => 1,
|
|
|
|
I16 => 2,
|
|
|
|
I32 => 4,
|
|
|
|
I64 => 8,
|
2017-01-12 08:28:42 +01:00
|
|
|
I128 => 16,
|
2016-10-21 03:17:53 -06:00
|
|
|
Is => self.memory.pointer_size(),
|
|
|
|
};
|
|
|
|
PrimValKind::from_int_size(size)
|
|
|
|
}
|
|
|
|
|
|
|
|
ty::TyUint(uint_ty) => {
|
|
|
|
use syntax::ast::UintTy::*;
|
|
|
|
let size = match uint_ty {
|
|
|
|
U8 => 1,
|
|
|
|
U16 => 2,
|
|
|
|
U32 => 4,
|
|
|
|
U64 => 8,
|
2017-01-12 08:28:42 +01:00
|
|
|
U128 => 16,
|
2016-10-21 03:17:53 -06:00
|
|
|
Us => self.memory.pointer_size(),
|
|
|
|
};
|
|
|
|
PrimValKind::from_uint_size(size)
|
|
|
|
}
|
|
|
|
|
|
|
|
ty::TyFloat(FloatTy::F32) => PrimValKind::F32,
|
|
|
|
ty::TyFloat(FloatTy::F64) => PrimValKind::F64,
|
|
|
|
|
|
|
|
ty::TyFnPtr(_) => PrimValKind::FnPtr,
|
|
|
|
|
2017-02-03 15:47:23 +01:00
|
|
|
ty::TyRef(_, ref tam) |
|
|
|
|
ty::TyRawPtr(ref tam) if self.type_is_sized(tam.ty) => PrimValKind::Ptr,
|
|
|
|
|
|
|
|
ty::TyAdt(ref def, _) if def.is_box() => PrimValKind::Ptr,
|
2016-10-21 03:17:53 -06:00
|
|
|
|
|
|
|
ty::TyAdt(..) => {
|
|
|
|
use rustc::ty::layout::Layout::*;
|
2016-11-26 23:20:15 -08:00
|
|
|
match *self.type_layout(ty)? {
|
|
|
|
CEnum { discr, signed, .. } => {
|
|
|
|
let size = discr.size().bytes();
|
|
|
|
if signed {
|
|
|
|
PrimValKind::from_int_size(size)
|
|
|
|
} else {
|
|
|
|
PrimValKind::from_uint_size(size)
|
|
|
|
}
|
2016-10-21 03:17:53 -06:00
|
|
|
}
|
2016-11-26 23:20:15 -08:00
|
|
|
|
|
|
|
RawNullablePointer { value, .. } => {
|
|
|
|
use rustc::ty::layout::Primitive::*;
|
|
|
|
match value {
|
|
|
|
// TODO(solson): Does signedness matter here? What should the sign be?
|
|
|
|
Int(int) => PrimValKind::from_uint_size(int.size().bytes()),
|
|
|
|
F32 => PrimValKind::F32,
|
|
|
|
F64 => PrimValKind::F64,
|
|
|
|
Pointer => PrimValKind::Ptr,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => return Err(EvalError::TypeNotPrimitive(ty)),
|
2016-10-21 03:17:53 -06:00
|
|
|
}
|
2016-11-26 23:20:15 -08:00
|
|
|
}
|
2016-10-21 03:17:53 -06:00
|
|
|
|
2016-11-03 12:30:41 +01:00
|
|
|
_ => return Err(EvalError::TypeNotPrimitive(ty)),
|
2016-10-21 03:17:53 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(kind)
|
|
|
|
}
|
|
|
|
|
2017-02-04 13:09:10 -08:00
|
|
|
fn ensure_valid_value(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx> {
|
2016-10-21 03:17:53 -06:00
|
|
|
match ty.sty {
|
2016-12-17 03:09:57 -08:00
|
|
|
ty::TyBool if val.to_bytes()? > 1 => Err(EvalError::InvalidBool),
|
2016-10-21 03:17:53 -06:00
|
|
|
|
2016-12-17 03:09:57 -08:00
|
|
|
ty::TyChar if ::std::char::from_u32(val.to_bytes()? as u32).is_none()
|
2017-01-12 08:28:42 +01:00
|
|
|
=> Err(EvalError::InvalidChar(val.to_bytes()? as u32 as u128)),
|
2016-10-21 03:17:53 -06:00
|
|
|
|
|
|
|
_ => Ok(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
|
2016-11-28 20:22:21 -08:00
|
|
|
if let Some(val) = self.try_read_value(ptr, ty)? {
|
|
|
|
Ok(val)
|
|
|
|
} else {
|
|
|
|
bug!("primitive read failed for type: {:?}", ty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-03 15:47:23 +01:00
|
|
|
fn read_ptr(&mut self, ptr: Pointer, pointee_ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
|
|
|
|
let p = self.memory.read_ptr(ptr)?;
|
|
|
|
if self.type_is_sized(pointee_ty) {
|
|
|
|
Ok(Value::ByVal(PrimVal::Ptr(p)))
|
|
|
|
} else {
|
|
|
|
trace!("reading fat pointer extra of type {}", pointee_ty);
|
|
|
|
let extra = ptr.offset(self.memory.pointer_size());
|
|
|
|
let extra = match self.tcx.struct_tail(pointee_ty).sty {
|
|
|
|
ty::TyDynamic(..) => PrimVal::Ptr(self.memory.read_ptr(extra)?),
|
|
|
|
ty::TySlice(..) |
|
|
|
|
ty::TyStr => PrimVal::from_u128(self.memory.read_usize(extra)? as u128),
|
|
|
|
_ => bug!("unsized primval ptr read from {:?}", pointee_ty),
|
|
|
|
};
|
|
|
|
Ok(Value::ByValPair(PrimVal::Ptr(p), extra))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-28 20:22:21 -08:00
|
|
|
fn try_read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
|
2016-10-14 03:31:45 -06:00
|
|
|
use syntax::ast::FloatTy;
|
|
|
|
|
2016-10-18 22:31:21 -06:00
|
|
|
let val = match ty.sty {
|
2016-10-20 04:42:19 -06:00
|
|
|
ty::TyBool => PrimVal::from_bool(self.memory.read_bool(ptr)?),
|
2016-10-18 22:31:21 -06:00
|
|
|
ty::TyChar => {
|
2016-06-20 12:29:45 +02:00
|
|
|
let c = self.memory.read_uint(ptr, 4)? as u32;
|
|
|
|
match ::std::char::from_u32(c) {
|
2016-10-20 04:42:19 -06:00
|
|
|
Some(ch) => PrimVal::from_char(ch),
|
2017-01-12 08:28:42 +01:00
|
|
|
None => return Err(EvalError::InvalidChar(c as u128)),
|
2016-06-20 12:29:45 +02:00
|
|
|
}
|
|
|
|
}
|
2016-09-19 04:56:09 -06:00
|
|
|
|
2016-10-18 22:31:21 -06:00
|
|
|
ty::TyInt(int_ty) => {
|
2016-10-14 03:31:45 -06:00
|
|
|
use syntax::ast::IntTy::*;
|
|
|
|
let size = match int_ty {
|
|
|
|
I8 => 1,
|
|
|
|
I16 => 2,
|
|
|
|
I32 => 4,
|
|
|
|
I64 => 8,
|
2017-01-12 08:28:42 +01:00
|
|
|
I128 => 16,
|
2016-10-14 03:31:45 -06:00
|
|
|
Is => self.memory.pointer_size(),
|
|
|
|
};
|
2017-01-12 08:28:42 +01:00
|
|
|
PrimVal::from_i128(self.memory.read_int(ptr, size)?)
|
2016-10-14 03:31:45 -06:00
|
|
|
}
|
2016-09-19 04:38:51 -06:00
|
|
|
|
2016-10-18 22:31:21 -06:00
|
|
|
ty::TyUint(uint_ty) => {
|
2016-10-14 03:31:45 -06:00
|
|
|
use syntax::ast::UintTy::*;
|
|
|
|
let size = match uint_ty {
|
|
|
|
U8 => 1,
|
|
|
|
U16 => 2,
|
|
|
|
U32 => 4,
|
|
|
|
U64 => 8,
|
2017-01-12 08:28:42 +01:00
|
|
|
U128 => 16,
|
2016-10-14 03:31:45 -06:00
|
|
|
Us => self.memory.pointer_size(),
|
|
|
|
};
|
2017-01-12 08:28:42 +01:00
|
|
|
PrimVal::from_u128(self.memory.read_uint(ptr, size)?)
|
2016-10-14 03:31:45 -06:00
|
|
|
}
|
2016-09-19 04:38:51 -06:00
|
|
|
|
2016-10-20 04:42:19 -06:00
|
|
|
ty::TyFloat(FloatTy::F32) => PrimVal::from_f32(self.memory.read_f32(ptr)?),
|
|
|
|
ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(ptr)?),
|
2016-09-19 04:38:51 -06:00
|
|
|
|
2016-12-15 23:55:00 -08:00
|
|
|
ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::Ptr)?,
|
2017-02-03 15:47:23 +01:00
|
|
|
ty::TyRef(_, ref tam) |
|
|
|
|
ty::TyRawPtr(ref tam) => return self.read_ptr(ptr, tam.ty).map(Some),
|
2016-03-18 23:03:46 -06:00
|
|
|
|
2017-02-03 15:47:23 +01:00
|
|
|
ty::TyAdt(def, _) => {
|
|
|
|
if def.is_box() {
|
|
|
|
return self.read_ptr(ptr, ty.boxed_ty()).map(Some);
|
|
|
|
}
|
2016-09-07 18:34:59 +02:00
|
|
|
use rustc::ty::layout::Layout::*;
|
2016-11-17 17:23:40 +01:00
|
|
|
if let CEnum { discr, signed, .. } = *self.type_layout(ty)? {
|
2016-11-18 12:55:14 +01:00
|
|
|
let size = discr.size().bytes();
|
2016-10-14 03:31:45 -06:00
|
|
|
if signed {
|
2017-01-12 08:28:42 +01:00
|
|
|
PrimVal::from_i128(self.memory.read_int(ptr, size)?)
|
2016-10-14 03:31:45 -06:00
|
|
|
} else {
|
2017-01-12 08:28:42 +01:00
|
|
|
PrimVal::from_u128(self.memory.read_uint(ptr, size)?)
|
2016-09-07 18:34:59 +02:00
|
|
|
}
|
|
|
|
} else {
|
2016-11-28 20:22:21 -08:00
|
|
|
return Ok(None);
|
2016-09-07 18:34:59 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-11-28 20:22:21 -08:00
|
|
|
_ => return Ok(None),
|
2016-03-18 23:03:46 -06:00
|
|
|
};
|
2016-10-18 22:31:21 -06:00
|
|
|
|
2016-11-28 20:22:21 -08:00
|
|
|
Ok(Some(Value::ByVal(val)))
|
2016-03-18 23:03:46 -06:00
|
|
|
}
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn frame(&self) -> &Frame<'tcx> {
|
2016-03-07 07:10:52 -06:00
|
|
|
self.stack.last().expect("no call frames exist")
|
|
|
|
}
|
2016-03-14 20:39:51 -06:00
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn frame_mut(&mut self) -> &mut Frame<'tcx> {
|
2016-03-14 20:39:51 -06:00
|
|
|
self.stack.last_mut().expect("no call frames exist")
|
|
|
|
}
|
2015-11-12 15:50:58 -06:00
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn mir(&self) -> MirRef<'tcx> {
|
2016-11-03 10:38:08 +01:00
|
|
|
Ref::clone(&self.frame().mir)
|
2016-03-20 22:07:25 -06:00
|
|
|
}
|
2016-06-08 11:11:08 +02:00
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn substs(&self) -> &'tcx Substs<'tcx> {
|
2016-06-08 11:11:08 +02:00
|
|
|
self.frame().substs
|
|
|
|
}
|
2016-03-14 21:18:39 -06:00
|
|
|
|
2017-02-03 15:47:23 +01:00
|
|
|
fn unsize_into_ptr(
|
|
|
|
&mut self,
|
|
|
|
src: Value,
|
|
|
|
src_ty: Ty<'tcx>,
|
|
|
|
dest: Lvalue<'tcx>,
|
|
|
|
dest_ty: Ty<'tcx>,
|
|
|
|
sty: Ty<'tcx>,
|
|
|
|
dty: Ty<'tcx>,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2017-02-03 15:47:23 +01:00
|
|
|
// A<Struct> -> A<Trait> conversion
|
|
|
|
let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty);
|
|
|
|
|
|
|
|
match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
|
|
|
|
(&ty::TyArray(_, length), &ty::TySlice(_)) => {
|
|
|
|
let ptr = src.read_ptr(&self.memory)?;
|
|
|
|
let len = PrimVal::from_u128(length as u128);
|
|
|
|
let ptr = PrimVal::Ptr(ptr);
|
|
|
|
self.write_value(Value::ByValPair(ptr, len), dest, dest_ty)
|
|
|
|
}
|
|
|
|
(&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
|
|
|
|
// For now, upcasts are limited to changes in marker
|
|
|
|
// traits, and hence never actually require an actual
|
|
|
|
// change to the vtable.
|
|
|
|
self.write_value(src, dest, dest_ty)
|
|
|
|
},
|
|
|
|
(_, &ty::TyDynamic(ref data, _)) => {
|
|
|
|
let trait_ref = data.principal().unwrap().with_self_ty(self.tcx, src_pointee_ty);
|
|
|
|
let trait_ref = self.tcx.erase_regions(&trait_ref);
|
|
|
|
let vtable = self.get_vtable(trait_ref)?;
|
|
|
|
let ptr = src.read_ptr(&self.memory)?;
|
|
|
|
let ptr = PrimVal::Ptr(ptr);
|
|
|
|
let extra = PrimVal::Ptr(vtable);
|
|
|
|
self.write_value(Value::ByValPair(ptr, extra), dest, dest_ty)
|
|
|
|
},
|
|
|
|
|
|
|
|
_ => bug!("invalid unsizing {:?} -> {:?}", src_ty, dest_ty),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-27 18:01:33 +02:00
|
|
|
fn unsize_into(
|
|
|
|
&mut self,
|
|
|
|
src: Value,
|
|
|
|
src_ty: Ty<'tcx>,
|
2016-10-21 15:18:12 +02:00
|
|
|
dest: Lvalue<'tcx>,
|
2016-09-27 18:01:33 +02:00
|
|
|
dest_ty: Ty<'tcx>,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2016-09-27 18:01:33 +02:00
|
|
|
match (&src_ty.sty, &dest_ty.sty) {
|
2017-02-03 15:47:23 +01:00
|
|
|
(&ty::TyRef(_, ref s), &ty::TyRef(_, ref d)) |
|
|
|
|
(&ty::TyRef(_, ref s), &ty::TyRawPtr(ref d)) |
|
|
|
|
(&ty::TyRawPtr(ref s), &ty::TyRawPtr(ref d)) => self.unsize_into_ptr(src, src_ty, dest, dest_ty, s.ty, d.ty),
|
|
|
|
(&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) => {
|
|
|
|
if def_a.is_box() || def_b.is_box() {
|
|
|
|
if !def_a.is_box() || !def_b.is_box() {
|
|
|
|
panic!("invalid unsizing between {:?} -> {:?}", src_ty, dest_ty);
|
2016-09-27 18:01:33 +02:00
|
|
|
}
|
2017-02-03 15:47:23 +01:00
|
|
|
return self.unsize_into_ptr(src, src_ty, dest, dest_ty, src_ty.boxed_ty(), dest_ty.boxed_ty());
|
2016-09-27 18:01:33 +02:00
|
|
|
}
|
2016-10-21 15:18:12 +02:00
|
|
|
// FIXME(solson)
|
|
|
|
let dest = self.force_allocation(dest)?.to_ptr();
|
2016-09-27 18:01:33 +02:00
|
|
|
// unsizing of generic struct with pointer fields
|
|
|
|
// Example: `Arc<T>` -> `Arc<Trait>`
|
|
|
|
// here we need to increase the size of every &T thin ptr field to a fat ptr
|
|
|
|
|
|
|
|
assert_eq!(def_a, def_b);
|
|
|
|
|
|
|
|
let src_fields = def_a.variants[0].fields.iter();
|
|
|
|
let dst_fields = def_b.variants[0].fields.iter();
|
|
|
|
|
|
|
|
//let src = adt::MaybeSizedValue::sized(src);
|
|
|
|
//let dst = adt::MaybeSizedValue::sized(dst);
|
|
|
|
let src_ptr = match src {
|
|
|
|
Value::ByRef(ptr) => ptr,
|
2016-11-15 14:11:44 +01:00
|
|
|
_ => bug!("expected pointer, got {:?}", src),
|
2016-09-27 18:01:33 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
let iter = src_fields.zip(dst_fields).enumerate();
|
|
|
|
for (i, (src_f, dst_f)) in iter {
|
2016-11-04 15:48:45 +01:00
|
|
|
let src_fty = monomorphize_field_ty(self.tcx, src_f, substs_a);
|
|
|
|
let dst_fty = monomorphize_field_ty(self.tcx, dst_f, substs_b);
|
2016-11-17 17:23:40 +01:00
|
|
|
if self.type_size(dst_fty)? == Some(0) {
|
2016-09-27 18:01:33 +02:00
|
|
|
continue;
|
|
|
|
}
|
2016-11-18 12:55:14 +01:00
|
|
|
let src_field_offset = self.get_field_offset(src_ty, i)?.bytes();
|
|
|
|
let dst_field_offset = self.get_field_offset(dest_ty, i)?.bytes();
|
2016-09-27 18:01:33 +02:00
|
|
|
let src_f_ptr = src_ptr.offset(src_field_offset);
|
|
|
|
let dst_f_ptr = dest.offset(dst_field_offset);
|
|
|
|
if src_fty == dst_fty {
|
2016-10-14 03:31:45 -06:00
|
|
|
self.copy(src_f_ptr, dst_f_ptr, src_fty)?;
|
2016-09-27 18:01:33 +02:00
|
|
|
} else {
|
2016-10-21 15:18:12 +02:00
|
|
|
self.unsize_into(Value::ByRef(src_f_ptr), src_fty, Lvalue::from_ptr(dst_f_ptr), dst_fty)?;
|
2016-09-27 18:01:33 +02:00
|
|
|
}
|
|
|
|
}
|
2017-02-03 15:47:23 +01:00
|
|
|
Ok(())
|
2016-09-27 18:01:33 +02:00
|
|
|
}
|
2016-12-07 22:00:46 -08:00
|
|
|
_ => bug!("unsize_into: invalid conversion: {:?} -> {:?}", src_ty, dest_ty),
|
2016-03-20 22:59:13 -06:00
|
|
|
}
|
|
|
|
}
|
2016-10-16 17:18:56 -06:00
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) fn dump_local(&self, lvalue: Lvalue<'tcx>) {
|
2017-02-10 16:14:59 +01:00
|
|
|
if let Lvalue::Local { frame, local, field } = lvalue {
|
2017-02-07 00:39:40 -08:00
|
|
|
let mut allocs = Vec::new();
|
|
|
|
let mut msg = format!("{:?}", local);
|
2017-02-10 22:15:30 +01:00
|
|
|
if let Some((field, _)) = field {
|
2017-02-10 21:59:29 +01:00
|
|
|
write!(msg, ".{}", field).unwrap();
|
|
|
|
}
|
2017-02-07 00:39:40 -08:00
|
|
|
let last_frame = self.stack.len() - 1;
|
|
|
|
if frame != last_frame {
|
|
|
|
write!(msg, " ({} frames up)", last_frame - frame).unwrap();
|
|
|
|
}
|
|
|
|
write!(msg, ":").unwrap();
|
|
|
|
|
2017-02-10 16:14:59 +01:00
|
|
|
match self.stack[frame].get_local(local, field.map(|(i, _)| i)) {
|
2016-12-18 20:59:01 -08:00
|
|
|
Value::ByRef(ptr) => {
|
|
|
|
allocs.push(ptr.alloc_id);
|
|
|
|
}
|
|
|
|
Value::ByVal(val) => {
|
2017-02-07 00:39:40 -08:00
|
|
|
write!(msg, " {:?}", val).unwrap();
|
2016-12-18 20:59:01 -08:00
|
|
|
if let PrimVal::Ptr(ptr) = val { allocs.push(ptr.alloc_id); }
|
|
|
|
}
|
|
|
|
Value::ByValPair(val1, val2) => {
|
2017-02-07 00:39:40 -08:00
|
|
|
write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
|
2016-12-18 20:59:01 -08:00
|
|
|
if let PrimVal::Ptr(ptr) = val1 { allocs.push(ptr.alloc_id); }
|
|
|
|
if let PrimVal::Ptr(ptr) = val2 { allocs.push(ptr.alloc_id); }
|
2016-10-18 21:45:48 -06:00
|
|
|
}
|
|
|
|
}
|
2016-12-07 22:00:46 -08:00
|
|
|
|
2017-02-07 00:39:40 -08:00
|
|
|
trace!("{}", msg);
|
|
|
|
self.memory.dump_allocs(allocs);
|
|
|
|
}
|
2016-10-18 21:45:48 -06:00
|
|
|
}
|
2016-11-03 12:52:13 +01:00
|
|
|
|
2016-12-18 20:59:01 -08:00
|
|
|
/// Convenience function to ensure correct usage of globals and code-sharing with locals.
|
2017-02-04 13:09:10 -08:00
|
|
|
pub fn modify_global<F>(&mut self, cid: GlobalId<'tcx>, f: F) -> EvalResult<'tcx>
|
2016-12-18 20:59:01 -08:00
|
|
|
where F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
|
|
|
|
{
|
2016-11-03 12:52:13 +01:00
|
|
|
let mut val = *self.globals.get(&cid).expect("global not cached");
|
|
|
|
if !val.mutable {
|
|
|
|
return Err(EvalError::ModifiedConstantMemory);
|
|
|
|
}
|
2016-12-18 20:59:01 -08:00
|
|
|
val.value = f(self, val.value)?;
|
2016-11-03 12:52:13 +01:00
|
|
|
*self.globals.get_mut(&cid).expect("already checked") = val;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2016-12-18 20:59:01 -08:00
|
|
|
/// Convenience function to ensure correct usage of locals and code-sharing with globals.
|
|
|
|
pub fn modify_local<F>(
|
2016-11-03 12:52:13 +01:00
|
|
|
&mut self,
|
|
|
|
frame: usize,
|
|
|
|
local: mir::Local,
|
2017-02-10 16:14:59 +01:00
|
|
|
field: Option<usize>,
|
2016-11-03 12:52:13 +01:00
|
|
|
f: F,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx>
|
2016-12-18 20:59:01 -08:00
|
|
|
where F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
|
|
|
|
{
|
2017-02-10 16:14:59 +01:00
|
|
|
let val = self.stack[frame].get_local(local, field);
|
2016-12-18 20:59:01 -08:00
|
|
|
let new_val = f(self, val)?;
|
2017-02-10 16:14:59 +01:00
|
|
|
self.stack[frame].set_local(local, field, new_val);
|
2016-12-18 20:59:01 -08:00
|
|
|
// FIXME(solson): Run this when setting to Undef? (See previous version of this code.)
|
|
|
|
// if let Value::ByRef(ptr) = self.stack[frame].get_local(local) {
|
|
|
|
// self.memory.deallocate(ptr)?;
|
|
|
|
// }
|
2016-11-03 12:52:13 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
2016-03-20 22:59:13 -06:00
|
|
|
}
|
|
|
|
|
2016-11-03 10:38:08 +01:00
|
|
|
impl<'tcx> Frame<'tcx> {
|
2017-02-10 16:14:59 +01:00
|
|
|
pub fn get_local(&self, local: mir::Local, field: Option<usize>) -> Value {
|
2016-10-15 19:48:30 -06:00
|
|
|
// Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
|
2017-02-10 16:14:59 +01:00
|
|
|
if let Some(field) = field {
|
|
|
|
match self.locals[local.index() - 1] {
|
|
|
|
Value::ByRef(_) => bug!("can't have lvalue fields for ByRef"),
|
|
|
|
val @ Value::ByVal(_) => {
|
|
|
|
assert_eq!(field, 0);
|
|
|
|
val
|
|
|
|
},
|
|
|
|
Value::ByValPair(a, b) => {
|
|
|
|
match field {
|
|
|
|
0 => Value::ByVal(a),
|
|
|
|
1 => Value::ByVal(b),
|
|
|
|
_ => bug!("ByValPair has only two fields, tried to access {}", field),
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.locals[local.index() - 1]
|
|
|
|
}
|
2016-10-15 19:48:30 -06:00
|
|
|
}
|
|
|
|
|
2017-02-10 16:14:59 +01:00
|
|
|
fn set_local(&mut self, local: mir::Local, field: Option<usize>, value: Value) {
|
2016-10-15 19:48:30 -06:00
|
|
|
// Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
|
2017-02-10 16:14:59 +01:00
|
|
|
if let Some(field) = field {
|
|
|
|
match self.locals[local.index() - 1] {
|
|
|
|
Value::ByRef(_) => bug!("can't have lvalue fields for ByRef"),
|
|
|
|
Value::ByVal(_) => {
|
|
|
|
assert_eq!(field, 0);
|
|
|
|
self.set_local(local, None, value);
|
|
|
|
},
|
|
|
|
Value::ByValPair(a, b) => {
|
|
|
|
let prim = match value {
|
|
|
|
Value::ByRef(_) => bug!("can't set ValPair field to ByRef"),
|
|
|
|
Value::ByVal(val) => val,
|
|
|
|
Value::ByValPair(_, _) => bug!("can't set ValPair field to ValPair"),
|
|
|
|
};
|
|
|
|
match field {
|
|
|
|
0 => self.set_local(local, None, Value::ByValPair(prim, b)),
|
|
|
|
1 => self.set_local(local, None, Value::ByValPair(a, prim)),
|
|
|
|
_ => bug!("ByValPair has only two fields, tried to access {}", field),
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.locals[local.index() - 1] = value;
|
|
|
|
}
|
2016-10-15 19:48:30 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-17 21:35:37 -06:00
|
|
|
pub fn eval_main<'a, 'tcx: 'a>(
|
|
|
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
2016-08-27 01:44:46 -06:00
|
|
|
def_id: DefId,
|
2016-11-26 17:54:19 -08:00
|
|
|
limits: ResourceLimits,
|
2016-06-17 21:35:37 -06:00
|
|
|
) {
|
2016-11-26 17:54:19 -08:00
|
|
|
let mut ecx = EvalContext::new(tcx, limits);
|
2016-11-03 10:38:08 +01:00
|
|
|
let mir = ecx.load_mir(def_id).expect("main function's MIR not found");
|
2016-06-17 21:35:37 -06:00
|
|
|
|
2017-02-10 05:27:02 -08:00
|
|
|
if !mir.return_ty.is_nil() || mir.arg_count != 0 {
|
|
|
|
let msg = "miri does not support main functions without `fn()` type signatures";
|
|
|
|
tcx.sess.err(&EvalError::Unimplemented(String::from(msg)).to_string());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-14 03:31:45 -06:00
|
|
|
ecx.push_stack_frame(
|
|
|
|
def_id,
|
2017-02-07 01:30:16 -08:00
|
|
|
DUMMY_SP,
|
2016-11-03 10:38:08 +01:00
|
|
|
mir,
|
2016-11-01 23:26:04 +01:00
|
|
|
tcx.intern_substs(&[]),
|
2016-10-16 00:12:11 -06:00
|
|
|
Lvalue::from_ptr(Pointer::zst_ptr()),
|
2016-11-03 10:38:08 +01:00
|
|
|
StackPopCleanup::None,
|
2016-12-06 18:13:11 +01:00
|
|
|
Vec::new(),
|
2016-10-14 03:31:45 -06:00
|
|
|
).expect("could not allocate first stack frame");
|
2016-06-17 21:35:37 -06:00
|
|
|
|
2016-11-17 17:22:34 +01:00
|
|
|
loop {
|
2016-06-23 00:02:47 -06:00
|
|
|
match ecx.step() {
|
2016-10-18 21:51:36 -06:00
|
|
|
Ok(true) => {}
|
2017-02-14 15:35:13 +01:00
|
|
|
Ok(false) => {
|
|
|
|
let leaks = ecx.memory.leak_report();
|
|
|
|
if leaks != 0 {
|
|
|
|
tcx.sess.err("the evaluated program leaked memory");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2016-06-17 21:35:37 -06:00
|
|
|
Err(e) => {
|
|
|
|
report(tcx, &ecx, e);
|
2016-07-05 13:17:40 +02:00
|
|
|
return;
|
2016-06-17 21:35:37 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) {
|
|
|
|
let frame = ecx.stack().last().expect("stackframe was empty");
|
|
|
|
let block = &frame.mir.basic_blocks()[frame.block];
|
|
|
|
let span = if frame.stmt < block.statements.len() {
|
|
|
|
block.statements[frame.stmt].source_info.span
|
|
|
|
} else {
|
|
|
|
block.terminator().source_info.span
|
|
|
|
};
|
|
|
|
let mut err = tcx.sess.struct_span_err(span, &e.to_string());
|
|
|
|
for &Frame { def_id, substs, span, .. } in ecx.stack().iter().rev() {
|
2016-09-28 18:22:53 +02:00
|
|
|
if tcx.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr {
|
|
|
|
err.span_note(span, "inside call to closure");
|
|
|
|
continue;
|
|
|
|
}
|
2016-06-17 21:35:37 -06:00
|
|
|
// FIXME(solson): Find a way to do this without this Display impl hack.
|
|
|
|
use rustc::util::ppaux;
|
|
|
|
use std::fmt;
|
|
|
|
struct Instance<'tcx>(DefId, &'tcx subst::Substs<'tcx>);
|
2016-09-15 16:10:58 +02:00
|
|
|
impl<'tcx> ::std::panic::UnwindSafe for Instance<'tcx> {}
|
|
|
|
impl<'tcx> ::std::panic::RefUnwindSafe for Instance<'tcx> {}
|
2016-06-17 21:35:37 -06:00
|
|
|
impl<'tcx> fmt::Display for Instance<'tcx> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2016-11-03 10:38:08 +01:00
|
|
|
ppaux::parameterized(f, self.1, self.0, &[])
|
2016-06-17 21:35:37 -06:00
|
|
|
}
|
|
|
|
}
|
2016-09-20 12:51:48 +02:00
|
|
|
err.span_note(span, &format!("inside call to {}", Instance(def_id, substs)));
|
2016-06-17 21:35:37 -06:00
|
|
|
}
|
|
|
|
err.emit();
|
|
|
|
}
|
2016-06-23 01:03:58 -06:00
|
|
|
|
2016-11-03 10:38:08 +01:00
|
|
|
pub fn run_mir_passes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
2016-06-30 21:33:24 -06:00
|
|
|
let mut passes = ::rustc::mir::transform::Passes::new();
|
|
|
|
passes.push_hook(Box::new(::rustc_mir::transform::dump_mir::DumpMir));
|
|
|
|
passes.push_pass(Box::new(::rustc_mir::transform::no_landing_pads::NoLandingPads));
|
2016-11-06 22:25:54 -08:00
|
|
|
passes.push_pass(Box::new(::rustc_mir::transform::simplify::SimplifyCfg::new("no-landing-pads")));
|
2016-06-30 21:33:24 -06:00
|
|
|
|
2016-12-18 23:31:23 -08:00
|
|
|
// From here on out, regions are gone.
|
2016-06-30 21:33:24 -06:00
|
|
|
passes.push_pass(Box::new(::rustc_mir::transform::erase_regions::EraseRegions));
|
|
|
|
|
2016-12-18 23:31:23 -08:00
|
|
|
passes.push_pass(Box::new(::rustc_mir::transform::add_call_guards::AddCallGuards));
|
2016-06-30 21:33:24 -06:00
|
|
|
passes.push_pass(Box::new(::rustc_borrowck::ElaborateDrops));
|
|
|
|
passes.push_pass(Box::new(::rustc_mir::transform::no_landing_pads::NoLandingPads));
|
2016-11-06 22:25:54 -08:00
|
|
|
passes.push_pass(Box::new(::rustc_mir::transform::simplify::SimplifyCfg::new("elaborate-drops")));
|
2016-12-18 23:31:23 -08:00
|
|
|
|
|
|
|
// No lifetime analysis based on borrowing can be done from here on out.
|
|
|
|
passes.push_pass(Box::new(::rustc_mir::transform::instcombine::InstCombine::new()));
|
|
|
|
passes.push_pass(Box::new(::rustc_mir::transform::deaggregator::Deaggregator));
|
|
|
|
passes.push_pass(Box::new(::rustc_mir::transform::copy_prop::CopyPropagation));
|
|
|
|
|
|
|
|
passes.push_pass(Box::new(::rustc_mir::transform::simplify::SimplifyLocals));
|
|
|
|
passes.push_pass(Box::new(::rustc_mir::transform::add_call_guards::AddCallGuards));
|
2016-06-30 21:33:24 -06:00
|
|
|
passes.push_pass(Box::new(::rustc_mir::transform::dump_mir::Marker("PreMiri")));
|
|
|
|
|
2016-11-03 10:38:08 +01:00
|
|
|
passes.run_passes(tcx);
|
2016-06-30 21:33:24 -06:00
|
|
|
}
|
|
|
|
|
2016-06-23 01:03:58 -06:00
|
|
|
// TODO(solson): Upstream these methods into rustc::ty::layout.
|
|
|
|
|
2016-12-07 20:30:37 -08:00
|
|
|
pub(super) trait IntegerExt {
|
2016-06-23 01:03:58 -06:00
|
|
|
fn size(self) -> Size;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl IntegerExt for layout::Integer {
|
|
|
|
fn size(self) -> Size {
|
|
|
|
use rustc::ty::layout::Integer::*;
|
|
|
|
match self {
|
|
|
|
I1 | I8 => Size::from_bits(8),
|
|
|
|
I16 => Size::from_bits(16),
|
|
|
|
I32 => Size::from_bits(32),
|
|
|
|
I64 => Size::from_bits(64),
|
2017-01-12 08:28:42 +01:00
|
|
|
I128 => Size::from_bits(128),
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-11-04 15:48:45 +01:00
|
|
|
|
|
|
|
|
2016-12-06 15:41:28 +01:00
|
|
|
pub fn monomorphize_field_ty<'a, 'tcx:'a >(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: &ty::FieldDef, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
|
2017-01-22 00:19:35 -08:00
|
|
|
let substituted = f.ty(tcx, substs);
|
2016-11-04 15:48:45 +01:00
|
|
|
tcx.normalize_associated_type(&substituted)
|
|
|
|
}
|
2017-01-12 10:37:14 +01:00
|
|
|
|
|
|
|
pub fn is_inhabited<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
|
2017-02-14 10:17:00 +01:00
|
|
|
ty.uninhabited_from(&mut HashMap::default(), tcx).is_empty()
|
2017-01-12 10:37:14 +01:00
|
|
|
}
|
2016-12-19 17:26:47 +01:00
|
|
|
|
|
|
|
pub trait IntoValTyPair<'tcx> {
|
|
|
|
fn into_val_ty_pair<'a>(self, ecx: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> IntoValTyPair<'tcx> for (Value, Ty<'tcx>) {
|
|
|
|
fn into_val_ty_pair<'a>(self, _: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a {
|
|
|
|
Ok(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'b, 'tcx: 'b> IntoValTyPair<'tcx> for &'b mir::Operand<'tcx> {
|
|
|
|
fn into_val_ty_pair<'a>(self, ecx: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a {
|
|
|
|
let value = ecx.eval_operand(self)?;
|
|
|
|
let value_ty = ecx.operand_ty(self);
|
|
|
|
Ok((value, value_ty))
|
|
|
|
}
|
|
|
|
}
|