1 use std::collections::HashSet;
4 use rustc::hir::def_id::DefId;
5 use rustc::hir::map::definitions::DefPathData;
6 use rustc::middle::const_val::ConstVal;
8 use rustc::traits::Reveal;
9 use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout};
10 use rustc::ty::subst::{Subst, Substs};
11 use rustc::ty::{self, Ty, TyCtxt};
12 use rustc_data_structures::indexed_vec::Idx;
13 use syntax::codemap::{self, DUMMY_SP};
14 use syntax::ast::Mutability;
15 use rustc::mir::interpret::{
16 GlobalId, Value, Pointer, PrimVal, PrimValKind,
17 EvalError, EvalResult, EvalErrorKind, MemoryPointer,
20 use super::{Place, PlaceExtra, Memory,
21 HasMemory, MemoryKind, operator,
24 pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> {
25 /// Stores the `Machine` instance.
28 /// The results of the type checker, from rustc.
29 pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
31 /// Bounds in scope for polymorphic evaluations.
32 pub param_env: ty::ParamEnv<'tcx>,
34 /// The virtual memory system.
35 pub memory: Memory<'a, 'tcx, M>,
37 /// The virtual call stack.
38 pub(crate) stack: Vec<Frame<'tcx>>,
40 /// The maximum number of stack frames allowed
41 pub(crate) stack_limit: usize,
43 /// The maximum number of operations that may be executed.
44 /// This prevents infinite loops and huge computations from freezing up const eval.
45 /// Remove once halting problem is solved.
46 pub(crate) steps_remaining: u64,
50 pub struct Frame<'tcx> {
51 ////////////////////////////////////////////////////////////////////////////////
52 // Function and callsite information
53 ////////////////////////////////////////////////////////////////////////////////
54 /// The MIR for the function called on this frame.
55 pub mir: &'tcx mir::Mir<'tcx>,
57 /// The def_id and substs of the current function
58 pub instance: ty::Instance<'tcx>,
60 /// The span of the call site.
61 pub span: codemap::Span,
63 ////////////////////////////////////////////////////////////////////////////////
64 // Return place and locals
65 ////////////////////////////////////////////////////////////////////////////////
66 /// The block to return to when returning from the current stack frame
67 pub return_to_block: StackPopCleanup,
69 /// The location where the result of the current stack frame should be written to.
70 pub return_place: Place,
72 /// The list of locals for this stack frame, stored in order as
73 /// `[arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
74 /// `None` represents a local that is currently dead, while a live local
75 /// can either directly contain `PrimVal` or refer to some part of an `Allocation`.
77 /// Before being initialized, arguments are `Value::ByVal(PrimVal::Undef)` and other locals are `None`.
78 pub locals: Vec<Option<Value>>,
80 ////////////////////////////////////////////////////////////////////////////////
81 // Current position within the function
82 ////////////////////////////////////////////////////////////////////////////////
83 /// The block that is currently executed (or will be executed after the above call stacks
85 pub block: mir::BasicBlock,
87 /// The index of the currently evaluated statement.
91 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
92 pub enum StackPopCleanup {
93 /// The stackframe existed to compute the initial value of a static/constant, make sure it
94 /// isn't modifyable afterwards in case of constants.
95 /// In case of `static mut`, mark the memory to ensure it's never marked as immutable through
96 /// references or deallocated
97 MarkStatic(Mutability),
98 /// A regular stackframe added due to a function call will need to get forwarded to the next
100 Goto(mir::BasicBlock),
101 /// The main function and diverging functions have nowhere to return to
105 #[derive(Copy, Clone, Debug)]
106 pub struct ResourceLimits {
107 pub memory_size: u64,
109 pub stack_limit: usize,
112 impl Default for ResourceLimits {
113 fn default() -> Self {
115 memory_size: 100 * 1024 * 1024, // 100 MB
116 step_limit: 1_000_000,
122 #[derive(Copy, Clone, Debug)]
123 pub struct TyAndPacked<'tcx> {
128 #[derive(Copy, Clone, Debug)]
129 pub struct ValTy<'tcx> {
134 impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
136 fn deref(&self) -> &Value {
141 impl<'a, 'tcx, M: Machine<'tcx>> HasDataLayout for &'a EvalContext<'a, 'tcx, M> {
143 fn data_layout(&self) -> &layout::TargetDataLayout {
144 &self.tcx.data_layout
148 impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> HasDataLayout
149 for &'c &'b mut EvalContext<'a, 'tcx, M> {
151 fn data_layout(&self) -> &layout::TargetDataLayout {
152 &self.tcx.data_layout
156 impl<'a, 'tcx, M: Machine<'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'tcx, M> {
158 fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
163 impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> layout::HasTyCtxt<'tcx>
164 for &'c &'b mut EvalContext<'a, 'tcx, M> {
166 fn tcx<'d>(&'d self) -> TyCtxt<'d, 'tcx, 'tcx> {
171 impl<'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalContext<'a, 'tcx, M> {
172 type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
174 fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
175 self.tcx.layout_of(self.param_env.and(ty))
176 .map_err(|layout| EvalErrorKind::Layout(layout).into())
180 impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>>
181 for &'c &'b mut EvalContext<'a, 'tcx, M> {
182 type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
185 fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
186 (&**self).layout_of(ty)
190 impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
192 tcx: TyCtxt<'a, 'tcx, 'tcx>,
193 param_env: ty::ParamEnv<'tcx>,
194 limits: ResourceLimits,
196 memory_data: M::MemoryData,
202 memory: Memory::new(tcx, limits.memory_size, memory_data),
204 stack_limit: limits.stack_limit,
205 steps_remaining: limits.step_limit,
209 pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, MemoryPointer> {
210 let layout = self.layout_of(ty)?;
211 assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
213 let size = layout.size.bytes();
214 self.memory.allocate(size, layout.align, Some(MemoryKind::Stack))
217 pub fn memory(&self) -> &Memory<'a, 'tcx, M> {
221 pub fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> {
225 pub fn stack(&self) -> &[Frame<'tcx>] {
230 pub fn cur_frame(&self) -> usize {
231 assert!(self.stack.len() > 0);
235 pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
236 let ptr = self.memory.allocate_cached(s.as_bytes());
239 PrimVal::from_u128(s.len() as u128),
243 pub(super) fn const_to_value(&mut self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
244 use rustc::middle::const_val::ConstVal::*;
246 let primval = match *const_val {
247 Integral(const_int) => PrimVal::Bytes(const_int.to_u128_unchecked()),
249 Float(val) => PrimVal::Bytes(val.bits),
251 Bool(b) => PrimVal::from_bool(b),
252 Char(c) => PrimVal::from_char(c),
254 Str(ref s) => return self.str_to_value(s),
257 let ptr = self.memory.allocate_cached(bs.data);
261 Unevaluated(def_id, substs) => {
262 let instance = self.resolve(def_id, substs)?;
263 return Ok(self.read_global_as_value(GlobalId {
266 }, self.layout_of(ty)?));
270 Variant(_) => bug!("should not have aggregate or variant constants in MIR"),
271 // function items are zero sized and thus have no readable value
272 Function(..) => PrimVal::Undef,
275 Ok(Value::ByVal(primval))
278 pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, ty::Instance<'tcx>> {
279 let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs);
280 ty::Instance::resolve(
285 ).ok_or(EvalErrorKind::TypeckError.into()) // turn error prop into a panic to expose associated type in const issue
288 pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
289 ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env)
294 instance: ty::InstanceDef<'tcx>,
295 ) -> EvalResult<'tcx, &'tcx mir::Mir<'tcx>> {
296 // do not continue if typeck errors occurred (can only occur in local crate)
297 let did = instance.def_id();
298 if did.is_local() && self.tcx.has_typeck_tables(did) && self.tcx.typeck_tables_of(did).tainted_by_errors {
299 return err!(TypeckError);
301 trace!("load mir {:?}", instance);
303 ty::InstanceDef::Item(def_id) => {
304 self.tcx.maybe_optimized_mir(def_id).ok_or_else(|| {
305 EvalErrorKind::NoMirFor(self.tcx.item_path_str(def_id)).into()
308 _ => Ok(self.tcx.instance_mir(instance)),
312 pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
313 // miri doesn't care about lifetimes, and will choke on some crazy ones
314 // let's simply get rid of them
315 let without_lifetimes = self.tcx.erase_regions(&ty);
316 let substituted = without_lifetimes.subst(self.tcx, substs);
317 let substituted = self.tcx.fully_normalize_monormophic_ty(&substituted);
321 /// Return the size and aligment of the value at the given type.
322 /// Note that the value does not matter if the type is sized. For unsized types,
323 /// the value has to be a fat pointer, and we only care about the "extra" data in it.
324 pub fn size_and_align_of_dst(
328 ) -> EvalResult<'tcx, (Size, Align)> {
329 let layout = self.layout_of(ty)?;
330 if !layout.is_unsized() {
331 Ok(layout.size_and_align())
334 ty::TyAdt(..) | ty::TyTuple(..) => {
335 // First get the size of all statically known fields.
336 // Don't use type_of::sizing_type_of because that expects t to be sized,
337 // and it also rounds up to alignment, which we want to avoid,
338 // as the unsized field's alignment could be smaller.
339 assert!(!ty.is_simd());
340 debug!("DST {} layout: {:?}", ty, layout);
342 let sized_size = layout.fields.offset(layout.fields.count() - 1);
343 let sized_align = layout.align;
345 "DST {} statically sized prefix size: {:?} align: {:?}",
351 // Recurse to get the size of the dynamically sized field (must be
353 let field_ty = layout.field(&self, layout.fields.count() - 1)?.ty;
354 let (unsized_size, unsized_align) =
355 self.size_and_align_of_dst(field_ty, value)?;
357 // FIXME (#26403, #27023): We should be adding padding
358 // to `sized_size` (to accommodate the `unsized_align`
359 // required of the unsized field that follows) before
360 // summing it with `sized_size`. (Note that since #26403
361 // is unfixed, we do not yet add the necessary padding
362 // here. But this is where the add would go.)
364 // Return the sum of sizes and max of aligns.
365 let size = sized_size + unsized_size;
367 // Choose max of two known alignments (combined value must
368 // be aligned according to more restrictive of the two).
369 let align = sized_align.max(unsized_align);
371 // Issue #27023: must add any necessary padding to `size`
372 // (to make it a multiple of `align`) before returning it.
374 // Namely, the returned size should be, in C notation:
376 // `size + ((size & (align-1)) ? align : 0)`
378 // emulated via the semi-standard fast bit trick:
380 // `(size + (align-1)) & -align`
382 Ok((size.abi_align(align), align))
384 ty::TyDynamic(..) => {
385 let (_, vtable) = self.into_ptr_vtable_pair(value)?;
386 // the second entry in the vtable is the dynamic size of the object.
387 self.read_size_and_align_from_vtable(vtable)
390 ty::TySlice(_) | ty::TyStr => {
391 let (elem_size, align) = layout.field(&self, 0)?.size_and_align();
392 let (_, len) = self.into_slice(value)?;
393 Ok((elem_size * len, align))
396 _ => bug!("size_of_val::<{:?}>", ty),
401 pub fn push_stack_frame(
403 instance: ty::Instance<'tcx>,
405 mir: &'tcx mir::Mir<'tcx>,
407 return_to_block: StackPopCleanup,
408 ) -> EvalResult<'tcx> {
409 ::log_settings::settings().indentation += 1;
411 /// Return the set of locals that have a storage annotation anywhere
412 fn collect_storage_annotations<'tcx>(mir: &'tcx mir::Mir<'tcx>) -> HashSet<mir::Local> {
413 use rustc::mir::StatementKind::*;
415 let mut set = HashSet::new();
416 for block in mir.basic_blocks() {
417 for stmt in block.statements.iter() {
420 StorageDead(local) => {
430 // Subtract 1 because `local_decls` includes the ReturnMemoryPointer, but we don't store a local
432 let num_locals = mir.local_decls.len() - 1;
435 let annotated_locals = collect_storage_annotations(mir);
436 let mut locals = vec![None; num_locals];
437 for i in 0..num_locals {
438 let local = mir::Local::new(i + 1);
439 if !annotated_locals.contains(&local) {
440 locals[i] = Some(Value::ByVal(PrimVal::Undef));
446 self.stack.push(Frame {
448 block: mir::START_BLOCK,
457 self.memory.cur_frame = self.cur_frame();
459 if self.stack.len() > self.stack_limit {
460 err!(StackFrameLimitReached)
466 pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
467 ::log_settings::settings().indentation -= 1;
468 M::end_region(self, None)?;
469 let frame = self.stack.pop().expect(
470 "tried to pop a stack frame, but there were none",
472 if !self.stack.is_empty() {
473 // TODO: Is this the correct time to start considering these accesses as originating from the returned-to stack frame?
474 self.memory.cur_frame = self.cur_frame();
476 match frame.return_to_block {
477 StackPopCleanup::MarkStatic(mutable) => {
478 if let Place::Ptr { ptr, .. } = frame.return_place {
479 // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
480 self.memory.mark_static_initalized(
481 ptr.to_ptr()?.alloc_id,
485 bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_place);
488 StackPopCleanup::Goto(target) => self.goto_block(target),
489 StackPopCleanup::None => {}
491 // deallocate all locals that are backed by an allocation
492 for local in frame.locals {
493 self.deallocate_local(local)?;
499 pub fn deallocate_local(&mut self, local: Option<Value>) -> EvalResult<'tcx> {
500 if let Some(Value::ByRef(ptr, _align)) = local {
501 trace!("deallocating local");
502 let ptr = ptr.to_ptr()?;
503 self.memory.dump_alloc(ptr.alloc_id);
504 self.memory.deallocate_local(ptr)?;
509 /// Evaluate an assignment statement.
511 /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
512 /// type writes its results directly into the memory specified by the place.
513 pub(super) fn eval_rvalue_into_place(
515 rvalue: &mir::Rvalue<'tcx>,
516 place: &mir::Place<'tcx>,
517 ) -> EvalResult<'tcx> {
518 let dest = self.eval_place(place)?;
519 let dest_ty = self.place_ty(place);
521 use rustc::mir::Rvalue::*;
523 Use(ref operand) => {
524 let value = self.eval_operand(operand)?.value;
529 self.write_value(valty, dest)?;
532 BinaryOp(bin_op, ref left, ref right) => {
533 let left = self.eval_operand(left)?;
534 let right = self.eval_operand(right)?;
535 if self.intrinsic_overflowing(
543 // There was an overflow in an unchecked binop. Right now, we consider this an error and bail out.
544 // The rationale is that the reason rustc emits unchecked binops in release mode (vs. the checked binops
545 // it emits in debug mode) is performance, but it doesn't cost us any performance in miri.
546 // If, however, the compiler ever starts transforming unchecked intrinsics into unchecked binops,
547 // we have to go back to just ignoring the overflow here.
548 return err!(OverflowingMath);
552 CheckedBinaryOp(bin_op, ref left, ref right) => {
553 let left = self.eval_operand(left)?;
554 let right = self.eval_operand(right)?;
555 self.intrinsic_with_overflow(
564 UnaryOp(un_op, ref operand) => {
565 let val = self.eval_operand_to_primval(operand)?;
566 let kind = self.ty_to_primval_kind(dest_ty)?;
569 operator::unary_op(un_op, val, kind)?,
574 Aggregate(ref kind, ref operands) => {
575 self.inc_step_counter_and_check_limit(operands.len() as u64)?;
577 let (dest, active_field_index) = match **kind {
578 mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
579 self.write_discriminant_value(dest_ty, dest, variant_index)?;
580 if adt_def.is_enum() {
581 (self.place_downcast(dest, variant_index)?, active_field_index)
583 (dest, active_field_index)
589 let layout = self.layout_of(dest_ty)?;
590 for (i, operand) in operands.iter().enumerate() {
591 let value = self.eval_operand(operand)?;
592 // Ignore zero-sized fields.
593 if !self.layout_of(value.ty)?.is_zst() {
594 let field_index = active_field_index.unwrap_or(i);
595 let (field_dest, _) = self.place_field(dest, mir::Field::new(field_index), layout)?;
596 self.write_value(value, field_dest)?;
601 Repeat(ref operand, _) => {
602 let (elem_ty, length) = match dest_ty.sty {
603 ty::TyArray(elem_ty, n) => (elem_ty, n.val.to_const_int().unwrap().to_u64().unwrap()),
606 "tried to assign array-repeat to non-array type {:?}",
611 let elem_size = self.layout_of(elem_ty)?.size.bytes();
612 let value = self.eval_operand(operand)?.value;
614 let (dest, dest_align) = self.force_allocation(dest)?.to_ptr_align();
616 // FIXME: speed up repeat filling
618 let elem_dest = dest.offset(i * elem_size, &self)?;
619 self.write_value_to_ptr(value, elem_dest, dest_align, elem_ty)?;
624 // FIXME(CTFE): don't allow computing the length of arrays in const eval
625 let src = self.eval_place(place)?;
626 let ty = self.place_ty(place);
627 let (_, len) = src.elem_ty_and_len(ty);
630 PrimVal::from_u128(len as u128),
635 Ref(_, _, ref place) => {
636 let src = self.eval_place(place)?;
637 // We ignore the alignment of the place here -- special handling for packed structs ends
638 // at the `&` operator.
639 let (ptr, _align, extra) = self.force_allocation(src)?.to_ptr_align_extra();
641 let val = match extra {
642 PlaceExtra::None => ptr.to_value(),
643 PlaceExtra::Length(len) => ptr.to_value_with_len(len),
644 PlaceExtra::Vtable(vtable) => ptr.to_value_with_vtable(vtable),
645 PlaceExtra::DowncastVariant(..) => {
646 bug!("attempted to take a reference to an enum downcast place")
653 self.write_value(valty, dest)?;
656 NullaryOp(mir::NullOp::Box, ty) => {
657 let ty = self.monomorphize(ty, self.substs());
658 M::box_alloc(self, ty, dest)?;
661 NullaryOp(mir::NullOp::SizeOf, ty) => {
662 let ty = self.monomorphize(ty, self.substs());
663 let layout = self.layout_of(ty)?;
664 assert!(!layout.is_unsized(),
665 "SizeOf nullary MIR operator called for unsized type");
668 PrimVal::from_u128(layout.size.bytes() as u128),
673 Cast(kind, ref operand, cast_ty) => {
674 debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest_ty);
675 use rustc::mir::CastKind::*;
678 let src = self.eval_operand(operand)?;
679 let src_layout = self.layout_of(src.ty)?;
680 let dst_layout = self.layout_of(dest_ty)?;
681 self.unsize_into(src.value, src_layout, dest, dst_layout)?;
685 let src = self.eval_operand(operand)?;
686 if self.type_is_fat_ptr(src.ty) {
687 match (src.value, self.type_is_fat_ptr(dest_ty)) {
688 (Value::ByRef { .. }, _) |
689 (Value::ByValPair(..), true) => {
694 self.write_value(valty, dest)?;
696 (Value::ByValPair(data, _), false) => {
698 value: Value::ByVal(data),
701 self.write_value(valty, dest)?;
703 (Value::ByVal(_), _) => bug!("expected fat ptr"),
706 let src_val = self.value_to_primval(src)?;
707 let dest_val = self.cast_primval(src_val, src.ty, dest_ty)?;
709 value: Value::ByVal(dest_val),
712 self.write_value(valty, dest)?;
717 match self.eval_operand(operand)?.ty.sty {
718 ty::TyFnDef(def_id, substs) => {
719 if self.tcx.has_attr(def_id, "rustc_args_required_const") {
720 bug!("reifying a fn ptr that requires \
723 let instance = self.resolve(def_id, substs)?;
724 let fn_ptr = self.memory.create_fn_alloc(instance);
726 value: Value::ByVal(PrimVal::Ptr(fn_ptr)),
729 self.write_value(valty, dest)?;
731 ref other => bug!("reify fn pointer on {:?}", other),
738 let mut src = self.eval_operand(operand)?;
740 self.write_value(src, dest)?;
742 ref other => bug!("fn to unsafe fn cast on {:?}", other),
746 ClosureFnPointer => {
747 match self.eval_operand(operand)?.ty.sty {
748 ty::TyClosure(def_id, substs) => {
749 let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs);
750 let instance = ty::Instance::resolve_closure(
754 ty::ClosureKind::FnOnce,
756 let fn_ptr = self.memory.create_fn_alloc(instance);
758 value: Value::ByVal(PrimVal::Ptr(fn_ptr)),
761 self.write_value(valty, dest)?;
763 ref other => bug!("closure fn pointer on {:?}", other),
769 Discriminant(ref place) => {
770 let ty = self.place_ty(place);
771 let place = self.eval_place(place)?;
772 let discr_val = self.read_discriminant_value(place, ty)?;
773 if let ty::TyAdt(adt_def, _) = ty.sty {
774 trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(self.tcx).collect::<Vec<_>>());
775 if adt_def.discriminants(self.tcx).all(|v| {
776 discr_val != v.to_u128_unchecked()
779 return err!(InvalidDiscriminant);
781 self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
783 bug!("rustc only generates Rvalue::Discriminant for enums");
788 if log_enabled!(::log::Level::Trace) {
789 self.dump_local(dest);
795 pub(super) fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
797 ty::TyRawPtr(ref tam) |
798 ty::TyRef(_, ref tam) => !self.type_is_sized(tam.ty),
799 ty::TyAdt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()),
804 pub(super) fn eval_operand_to_primval(
806 op: &mir::Operand<'tcx>,
807 ) -> EvalResult<'tcx, PrimVal> {
808 let valty = self.eval_operand(op)?;
809 self.value_to_primval(valty)
812 pub(crate) fn operands_to_args(
814 ops: &[mir::Operand<'tcx>],
815 ) -> EvalResult<'tcx, Vec<ValTy<'tcx>>> {
817 .map(|op| self.eval_operand(op))
821 pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> {
822 use rustc::mir::Operand::*;
823 let ty = self.monomorphize(op.ty(self.mir(), self.tcx), self.substs());
825 // FIXME: do some more logic on `move` to invalidate the old location
829 value: self.eval_and_read_place(place)?,
834 Constant(ref constant) => {
835 use rustc::mir::Literal;
836 let mir::Constant { ref literal, .. } = **constant;
837 let value = match *literal {
838 Literal::Value { ref value } => self.const_to_value(&value.val, ty)?,
840 Literal::Promoted { index } => {
841 self.read_global_as_value(GlobalId {
842 instance: self.frame().instance,
843 promoted: Some(index),
844 }, self.layout_of(ty)?)
856 pub fn read_discriminant_value(
860 ) -> EvalResult<'tcx, u128> {
861 let layout = self.layout_of(ty)?;
862 //trace!("read_discriminant_value {:#?}", layout);
864 match layout.variants {
865 layout::Variants::Single { index } => {
866 return Ok(index as u128);
868 layout::Variants::Tagged { .. } |
869 layout::Variants::NicheFilling { .. } => {},
872 let (discr_place, discr) = self.place_field(place, mir::Field::new(0), layout)?;
873 let raw_discr = self.value_to_primval(ValTy {
874 value: self.read_place(discr_place)?,
877 let discr_val = match layout.variants {
878 layout::Variants::Single { .. } => bug!(),
879 layout::Variants::Tagged { .. } => raw_discr.to_bytes()?,
880 layout::Variants::NicheFilling {
886 let variants_start = niche_variants.start as u128;
887 let variants_end = niche_variants.end as u128;
890 assert!(niche_start == 0);
891 assert!(variants_start == variants_end);
892 dataful_variant as u128
894 PrimVal::Bytes(raw_discr) => {
895 let discr = raw_discr.wrapping_sub(niche_start)
896 .wrapping_add(variants_start);
897 if variants_start <= discr && discr <= variants_end {
900 dataful_variant as u128
903 PrimVal::Undef => return err!(ReadUndefBytes),
912 pub(crate) fn write_discriminant_value(
916 variant_index: usize,
917 ) -> EvalResult<'tcx> {
918 let layout = self.layout_of(dest_ty)?;
920 match layout.variants {
921 layout::Variants::Single { index } => {
922 if index != variant_index {
923 // If the layout of an enum is `Single`, all
924 // other variants are necessarily uninhabited.
925 assert_eq!(layout.for_variant(&self, variant_index).abi,
926 layout::Abi::Uninhabited);
929 layout::Variants::Tagged { .. } => {
930 let discr_val = dest_ty.ty_adt_def().unwrap()
931 .discriminant_for_variant(self.tcx, variant_index)
932 .to_u128_unchecked();
934 let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?;
935 self.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?;
937 layout::Variants::NicheFilling {
943 if variant_index != dataful_variant {
944 let (niche_dest, niche) =
945 self.place_field(dest, mir::Field::new(0), layout)?;
946 let niche_value = ((variant_index - niche_variants.start) as u128)
947 .wrapping_add(niche_start);
948 self.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?;
956 pub fn read_global_as_value(&self, gid: GlobalId, layout: TyLayout) -> Value {
957 let alloc = self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached");
958 Value::ByRef(MemoryPointer::new(alloc, 0).into(), layout.align)
961 pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> {
962 let new_place = match place {
963 Place::Local { frame, local } => {
964 // -1 since we don't store the return value
965 match self.stack[frame].locals[local.index() - 1] {
966 None => return err!(DeadLocal),
967 Some(Value::ByRef(ptr, align)) => {
971 extra: PlaceExtra::None,
975 let ty = self.stack[frame].mir.local_decls[local].ty;
976 let ty = self.monomorphize(ty, self.stack[frame].instance.substs);
977 let layout = self.layout_of(ty)?;
978 let ptr = self.alloc_ptr(ty)?;
979 self.stack[frame].locals[local.index() - 1] =
980 Some(Value::ByRef(ptr.into(), layout.align)); // it stays live
981 let place = Place::from_ptr(ptr, layout.align);
982 self.write_value(ValTy { value: val, ty }, place)?;
987 Place::Ptr { .. } => place,
992 /// ensures this Value is not a ByRef
993 pub fn follow_by_ref_value(
997 ) -> EvalResult<'tcx, Value> {
999 Value::ByRef(ptr, align) => {
1000 self.read_value(ptr, align, ty)
1006 pub fn value_to_primval(
1008 ValTy { value, ty } : ValTy<'tcx>,
1009 ) -> EvalResult<'tcx, PrimVal> {
1010 match self.follow_by_ref_value(value, ty)? {
1011 Value::ByRef { .. } => bug!("follow_by_ref_value can't result in `ByRef`"),
1013 Value::ByVal(primval) => {
1014 // TODO: Do we really want insta-UB here?
1015 self.ensure_valid_value(primval, ty)?;
1019 Value::ByValPair(..) => bug!("value_to_primval can't work with fat pointers"),
1023 pub fn write_ptr(&mut self, dest: Place, val: Pointer, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> {
1025 value: val.to_value(),
1028 self.write_value(valty, dest)
1031 pub fn write_primval(
1036 ) -> EvalResult<'tcx> {
1038 value: Value::ByVal(val),
1041 self.write_value(valty, dest)
1046 ValTy { value: src_val, ty: dest_ty } : ValTy<'tcx>,
1048 ) -> EvalResult<'tcx> {
1049 //trace!("Writing {:?} to {:?} at type {:?}", src_val, dest, dest_ty);
1050 // Note that it is really important that the type here is the right one, and matches the type things are read at.
1051 // In case `src_val` is a `ByValPair`, we don't do any magic here to handle padding properly, which is only
1052 // correct if we never look at this data with the wrong type.
1055 Place::Ptr { ptr, align, extra } => {
1056 assert_eq!(extra, PlaceExtra::None);
1057 self.write_value_to_ptr(src_val, ptr, align, dest_ty)
1060 Place::Local { frame, local } => {
1061 let dest = self.stack[frame].get_local(local)?;
1062 self.write_value_possibly_by_val(
1064 |this, val| this.stack[frame].set_local(local, val),
1072 // The cases here can be a bit subtle. Read carefully!
1073 fn write_value_possibly_by_val<F: FnOnce(&mut Self, Value) -> EvalResult<'tcx>>(
1077 old_dest_val: Value,
1079 ) -> EvalResult<'tcx> {
1080 if let Value::ByRef(dest_ptr, align) = old_dest_val {
1081 // If the value is already `ByRef` (that is, backed by an `Allocation`),
1082 // then we must write the new value into this allocation, because there may be
1083 // other pointers into the allocation. These other pointers are logically
1084 // pointers into the local variable, and must be able to observe the change.
1086 // Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we
1087 // knew for certain that there were no outstanding pointers to this allocation.
1088 self.write_value_to_ptr(src_val, dest_ptr, align, dest_ty)?;
1089 } else if let Value::ByRef(src_ptr, align) = src_val {
1090 // If the value is not `ByRef`, then we know there are no pointers to it
1091 // and we can simply overwrite the `Value` in the locals array directly.
1093 // In this specific case, where the source value is `ByRef`, we must duplicate
1094 // the allocation, because this is a by-value operation. It would be incorrect
1095 // if they referred to the same allocation, since then a change to one would
1096 // implicitly change the other.
1098 // It is a valid optimization to attempt reading a primitive value out of the
1099 // source and write that into the destination without making an allocation, so
1101 if let Ok(Some(src_val)) = self.try_read_value(src_ptr, align, dest_ty) {
1102 write_dest(self, src_val)?;
1104 let dest_ptr = self.alloc_ptr(dest_ty)?.into();
1105 let layout = self.layout_of(dest_ty)?;
1106 self.memory.copy(src_ptr, align.min(layout.align), dest_ptr, layout.align, layout.size.bytes(), false)?;
1107 write_dest(self, Value::ByRef(dest_ptr, layout.align))?;
1110 // Finally, we have the simple case where neither source nor destination are
1111 // `ByRef`. We may simply copy the source value over the the destintion.
1112 write_dest(self, src_val)?;
1117 pub fn write_value_to_ptr(
1123 ) -> EvalResult<'tcx> {
1124 trace!("write_value_to_ptr: {:#?}", value);
1125 let layout = self.layout_of(dest_ty)?;
1127 Value::ByRef(ptr, align) => {
1128 self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size.bytes(), false)
1130 Value::ByVal(primval) => {
1132 layout::Abi::Scalar(_) => {}
1133 _ if primval.is_undef() => {}
1134 _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
1136 // TODO: Do we need signedness?
1137 self.memory.write_primval(dest.to_ptr()?, dest_align, primval, layout.size.bytes(), false)
1139 Value::ByValPair(a_val, b_val) => {
1140 let ptr = dest.to_ptr()?;
1141 trace!("write_value_to_ptr valpair: {:#?}", layout);
1142 let (a, b) = match layout.abi {
1143 layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
1144 _ => bug!("write_value_to_ptr: invalid ByValPair layout: {:#?}", layout)
1146 let (a_size, b_size) = (a.size(&self), b.size(&self));
1148 let b_offset = a_size.abi_align(b.align(&self));
1149 let b_ptr = ptr.offset(b_offset.bytes(), &self)?.into();
1150 // TODO: What about signedess?
1151 self.memory.write_primval(a_ptr, dest_align, a_val, a_size.bytes(), false)?;
1152 self.memory.write_primval(b_ptr, dest_align, b_val, b_size.bytes(), false)
1157 pub fn ty_to_primval_kind(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimValKind> {
1158 use syntax::ast::FloatTy;
1160 let kind = match ty.sty {
1161 ty::TyBool => PrimValKind::Bool,
1162 ty::TyChar => PrimValKind::Char,
1164 ty::TyInt(int_ty) => {
1165 use syntax::ast::IntTy::*;
1166 let size = match int_ty {
1172 Isize => self.memory.pointer_size(),
1174 PrimValKind::from_int_size(size)
1177 ty::TyUint(uint_ty) => {
1178 use syntax::ast::UintTy::*;
1179 let size = match uint_ty {
1185 Usize => self.memory.pointer_size(),
1187 PrimValKind::from_uint_size(size)
1190 ty::TyFloat(FloatTy::F32) => PrimValKind::F32,
1191 ty::TyFloat(FloatTy::F64) => PrimValKind::F64,
1193 ty::TyFnPtr(_) => PrimValKind::FnPtr,
1195 ty::TyRef(_, ref tam) |
1196 ty::TyRawPtr(ref tam) if self.type_is_sized(tam.ty) => PrimValKind::Ptr,
1198 ty::TyAdt(def, _) if def.is_box() => PrimValKind::Ptr,
1201 match self.layout_of(ty)?.abi {
1202 layout::Abi::Scalar(ref scalar) => {
1203 use rustc::ty::layout::Primitive::*;
1204 match scalar.value {
1205 Int(i, false) => PrimValKind::from_uint_size(i.size().bytes()),
1206 Int(i, true) => PrimValKind::from_int_size(i.size().bytes()),
1207 F32 => PrimValKind::F32,
1208 F64 => PrimValKind::F64,
1209 Pointer => PrimValKind::Ptr,
1213 _ => return err!(TypeNotPrimitive(ty)),
1217 _ => return err!(TypeNotPrimitive(ty)),
1223 fn ensure_valid_value(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx> {
1225 ty::TyBool if val.to_bytes()? > 1 => err!(InvalidBool),
1227 ty::TyChar if ::std::char::from_u32(val.to_bytes()? as u32).is_none() => {
1228 err!(InvalidChar(val.to_bytes()? as u32 as u128))
1235 pub fn read_value(&self, ptr: Pointer, align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
1236 if let Some(val) = self.try_read_value(ptr, align, ty)? {
1239 bug!("primitive read failed for type: {:?}", ty);
1243 pub(crate) fn read_ptr(
1247 pointee_ty: Ty<'tcx>,
1248 ) -> EvalResult<'tcx, Value> {
1249 let ptr_size = self.memory.pointer_size();
1250 let p: Pointer = self.memory.read_ptr_sized_unsigned(ptr, ptr_align)?.into();
1251 if self.type_is_sized(pointee_ty) {
1254 trace!("reading fat pointer extra of type {}", pointee_ty);
1255 let extra = ptr.offset(ptr_size, self)?;
1256 match self.tcx.struct_tail(pointee_ty).sty {
1257 ty::TyDynamic(..) => Ok(p.to_value_with_vtable(
1258 self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_ptr()?,
1260 ty::TySlice(..) | ty::TyStr => Ok(
1261 p.to_value_with_len(self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_bytes()? as u64),
1263 _ => bug!("unsized primval ptr read from {:?}", pointee_ty),
1268 pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
1269 use syntax::ast::FloatTy;
1271 let ptr = ptr.to_ptr()?;
1272 let val = match ty.sty {
1274 let val = self.memory.read_primval(ptr, ptr_align, 1, false)?;
1275 let val = match val {
1276 PrimVal::Bytes(0) => false,
1277 PrimVal::Bytes(1) => true,
1278 // TODO: This seems a little overeager, should reading at bool type already be insta-UB?
1279 _ => return err!(InvalidBool),
1281 PrimVal::from_bool(val)
1284 let c = self.memory.read_primval(ptr, ptr_align, 4, false)?.to_bytes()? as u32;
1285 match ::std::char::from_u32(c) {
1286 Some(ch) => PrimVal::from_char(ch),
1287 None => return err!(InvalidChar(c as u128)),
1291 ty::TyInt(int_ty) => {
1292 use syntax::ast::IntTy::*;
1293 let size = match int_ty {
1299 Isize => self.memory.pointer_size(),
1301 self.memory.read_primval(ptr, ptr_align, size, true)?
1304 ty::TyUint(uint_ty) => {
1305 use syntax::ast::UintTy::*;
1306 let size = match uint_ty {
1312 Usize => self.memory.pointer_size(),
1314 self.memory.read_primval(ptr, ptr_align, size, false)?
1317 ty::TyFloat(FloatTy::F32) => {
1318 PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4, false)?.to_bytes()?)
1320 ty::TyFloat(FloatTy::F64) => {
1321 PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8, false)?.to_bytes()?)
1324 ty::TyFnPtr(_) => self.memory.read_ptr_sized_unsigned(ptr, ptr_align)?,
1325 ty::TyRef(_, ref tam) |
1326 ty::TyRawPtr(ref tam) => return self.read_ptr(ptr, ptr_align, tam.ty).map(Some),
1328 ty::TyAdt(def, _) => {
1330 return self.read_ptr(ptr, ptr_align, ty.boxed_ty()).map(Some);
1333 if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi {
1334 let mut signed = false;
1335 if let layout::Int(_, s) = scalar.value {
1338 let size = scalar.value.size(self).bytes();
1339 self.memory.read_primval(ptr, ptr_align, size, signed)?
1345 _ => return Ok(None),
1348 Ok(Some(Value::ByVal(val)))
1351 pub fn frame(&self) -> &Frame<'tcx> {
1352 self.stack.last().expect("no call frames exist")
1355 pub fn frame_mut(&mut self) -> &mut Frame<'tcx> {
1356 self.stack.last_mut().expect("no call frames exist")
1359 pub(super) fn mir(&self) -> &'tcx mir::Mir<'tcx> {
1363 pub fn substs(&self) -> &'tcx Substs<'tcx> {
1364 if let Some(frame) = self.stack.last() {
1365 frame.instance.substs
1379 ) -> EvalResult<'tcx> {
1380 // A<Struct> -> A<Trait> conversion
1381 let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty);
1383 match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
1384 (&ty::TyArray(_, length), &ty::TySlice(_)) => {
1385 let ptr = self.into_ptr(src)?;
1386 // u64 cast is from usize to u64, which is always good
1388 value: ptr.to_value_with_len(length.val.to_const_int().unwrap().to_u64().unwrap() ),
1391 self.write_value(valty, dest)
1393 (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
1394 // For now, upcasts are limited to changes in marker
1395 // traits, and hence never actually require an actual
1396 // change to the vtable.
1401 self.write_value(valty, dest)
1403 (_, &ty::TyDynamic(ref data, _)) => {
1404 let trait_ref = data.principal().unwrap().with_self_ty(
1408 let trait_ref = self.tcx.erase_regions(&trait_ref);
1409 let vtable = self.get_vtable(src_pointee_ty, trait_ref)?;
1410 let ptr = self.into_ptr(src)?;
1412 value: ptr.to_value_with_vtable(vtable),
1415 self.write_value(valty, dest)
1418 _ => bug!("invalid unsizing {:?} -> {:?}", src_ty, dest_ty),
1425 src_layout: TyLayout<'tcx>,
1427 dst_layout: TyLayout<'tcx>,
1428 ) -> EvalResult<'tcx> {
1429 match (&src_layout.ty.sty, &dst_layout.ty.sty) {
1430 (&ty::TyRef(_, ref s), &ty::TyRef(_, ref d)) |
1431 (&ty::TyRef(_, ref s), &ty::TyRawPtr(ref d)) |
1432 (&ty::TyRawPtr(ref s), &ty::TyRawPtr(ref d)) => {
1433 self.unsize_into_ptr(src, src_layout.ty, dst, dst_layout.ty, s.ty, d.ty)
1435 (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => {
1436 assert_eq!(def_a, def_b);
1437 if def_a.is_box() || def_b.is_box() {
1438 if !def_a.is_box() || !def_b.is_box() {
1439 bug!("invalid unsizing between {:?} -> {:?}", src_layout, dst_layout);
1441 return self.unsize_into_ptr(
1446 src_layout.ty.boxed_ty(),
1447 dst_layout.ty.boxed_ty(),
1451 // unsizing of generic struct with pointer fields
1452 // Example: `Arc<T>` -> `Arc<Trait>`
1453 // here we need to increase the size of every &T thin ptr field to a fat ptr
1454 for i in 0..src_layout.fields.count() {
1455 let (dst_f_place, dst_field) =
1456 self.place_field(dst, mir::Field::new(i), dst_layout)?;
1457 if dst_field.is_zst() {
1460 let (src_f_value, src_field) = match src {
1461 Value::ByRef(ptr, align) => {
1462 let src_place = Place::from_primval_ptr(ptr, align);
1463 let (src_f_place, src_field) =
1464 self.place_field(src_place, mir::Field::new(i), src_layout)?;
1465 (self.read_place(src_f_place)?, src_field)
1467 Value::ByVal(_) | Value::ByValPair(..) => {
1468 let src_field = src_layout.field(&self, i)?;
1469 assert_eq!(src_layout.fields.offset(i).bytes(), 0);
1470 assert_eq!(src_field.size, src_layout.size);
1474 if src_field.ty == dst_field.ty {
1475 self.write_value(ValTy {
1480 self.unsize_into(src_f_value, src_field, dst_f_place, dst_field)?;
1487 "unsize_into: invalid conversion: {:?} -> {:?}",
1495 pub fn dump_local(&self, place: Place) {
1498 Place::Local { frame, local } => {
1499 let mut allocs = Vec::new();
1500 let mut msg = format!("{:?}", local);
1501 if frame != self.cur_frame() {
1502 write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap();
1504 write!(msg, ":").unwrap();
1506 match self.stack[frame].get_local(local) {
1507 Err(EvalError { kind: EvalErrorKind::DeadLocal, .. }) => {
1508 write!(msg, " is dead").unwrap();
1511 panic!("Failed to access local: {:?}", err);
1513 Ok(Value::ByRef(ptr, align)) => {
1514 match ptr.into_inner_primval() {
1515 PrimVal::Ptr(ptr) => {
1516 write!(msg, " by align({}) ref:", align.abi()).unwrap();
1517 allocs.push(ptr.alloc_id);
1519 ptr => write!(msg, " integral by ref: {:?}", ptr).unwrap(),
1522 Ok(Value::ByVal(val)) => {
1523 write!(msg, " {:?}", val).unwrap();
1524 if let PrimVal::Ptr(ptr) = val {
1525 allocs.push(ptr.alloc_id);
1528 Ok(Value::ByValPair(val1, val2)) => {
1529 write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
1530 if let PrimVal::Ptr(ptr) = val1 {
1531 allocs.push(ptr.alloc_id);
1533 if let PrimVal::Ptr(ptr) = val2 {
1534 allocs.push(ptr.alloc_id);
1540 self.memory.dump_allocs(allocs);
1542 Place::Ptr { ptr, align, .. } => {
1543 match ptr.into_inner_primval() {
1544 PrimVal::Ptr(ptr) => {
1545 trace!("by align({}) ref:", align.abi());
1546 self.memory.dump_alloc(ptr.alloc_id);
1548 ptr => trace!(" integral by ref: {:?}", ptr),
1554 /// Convenience function to ensure correct usage of locals
1555 pub fn modify_local<F>(&mut self, frame: usize, local: mir::Local, f: F) -> EvalResult<'tcx>
1557 F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
1559 let val = self.stack[frame].get_local(local)?;
1560 let new_val = f(self, val)?;
1561 self.stack[frame].set_local(local, new_val)?;
1562 // FIXME(solson): Run this when setting to Undef? (See previous version of this code.)
1563 // if let Value::ByRef(ptr) = self.stack[frame].get_local(local) {
1564 // self.memory.deallocate(ptr)?;
1569 pub fn report(&self, e: &mut EvalError) {
1570 if let Some(ref mut backtrace) = e.backtrace {
1571 let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
1572 backtrace.resolve();
1573 write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap();
1574 'frames: for (i, frame) in backtrace.frames().iter().enumerate() {
1575 if frame.symbols().is_empty() {
1576 write!(trace_text, "{}: no symbols\n", i).unwrap();
1578 for symbol in frame.symbols() {
1579 write!(trace_text, "{}: ", i).unwrap();
1580 if let Some(name) = symbol.name() {
1581 write!(trace_text, "{}\n", name).unwrap();
1583 write!(trace_text, "<unknown>\n").unwrap();
1585 write!(trace_text, "\tat ").unwrap();
1586 if let Some(file_path) = symbol.filename() {
1587 write!(trace_text, "{}", file_path.display()).unwrap();
1589 write!(trace_text, "<unknown_file>").unwrap();
1591 if let Some(line) = symbol.lineno() {
1592 write!(trace_text, ":{}\n", line).unwrap();
1594 write!(trace_text, "\n").unwrap();
1598 error!("{}", trace_text);
1600 if let Some(frame) = self.stack().last() {
1601 let block = &frame.mir.basic_blocks()[frame.block];
1602 let span = if frame.stmt < block.statements.len() {
1603 block.statements[frame.stmt].source_info.span
1605 block.terminator().source_info.span
1607 let mut err = self.tcx.sess.struct_span_err(span, &e.to_string());
1608 for &Frame { instance, span, .. } in self.stack().iter().rev() {
1609 if self.tcx.def_key(instance.def_id()).disambiguated_data.data ==
1610 DefPathData::ClosureExpr
1612 err.span_note(span, "inside call to closure");
1615 err.span_note(span, &format!("inside call to {}", instance));
1619 self.tcx.sess.err(&e.to_string());
1624 impl<'tcx> Frame<'tcx> {
1625 pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> {
1626 // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1627 self.locals[local.index() - 1].ok_or(EvalErrorKind::DeadLocal.into())
1630 fn set_local(&mut self, local: mir::Local, value: Value) -> EvalResult<'tcx> {
1631 // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1632 match self.locals[local.index() - 1] {
1633 None => err!(DeadLocal),
1634 Some(ref mut local) => {
1641 pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, Option<Value>> {
1642 trace!("{:?} is now live", local);
1644 let old = self.locals[local.index() - 1];
1645 self.locals[local.index() - 1] = Some(Value::ByVal(PrimVal::Undef)); // StorageLive *always* kills the value that's currently stored
1649 /// Returns the old value of the local
1650 pub fn storage_dead(&mut self, local: mir::Local) -> EvalResult<'tcx, Option<Value>> {
1651 trace!("{:?} is now dead", local);
1653 let old = self.locals[local.index() - 1];
1654 self.locals[local.index() - 1] = None;
1659 // TODO(solson): Upstream these methods into rustc::ty::layout.
1661 pub fn resolve_drop_in_place<'a, 'tcx>(
1662 tcx: TyCtxt<'a, 'tcx, 'tcx>,
1664 ) -> ty::Instance<'tcx> {
1665 let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem);
1666 let substs = tcx.intern_substs(&[ty.into()]);
1667 ty::Instance::resolve(tcx, ty::ParamEnv::empty(Reveal::All), def_id, substs).unwrap()