]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/eval_context.rs
A few minor tweaks
[rust.git] / src / librustc_mir / interpret / eval_context.rs
1 use std::cell::Cell;
2 use std::fmt::Write;
3 use std::mem;
4
5 use syntax::source_map::{self, Span, DUMMY_SP};
6 use rustc::hir::def_id::DefId;
7 use rustc::hir::def::DefKind;
8 use rustc::mir;
9 use rustc::ty::layout::{
10     self, Size, Align, HasDataLayout, LayoutOf, TyLayout
11 };
12 use rustc::ty::subst::SubstsRef;
13 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
14 use rustc::ty::query::TyCtxtAt;
15 use rustc_index::vec::IndexVec;
16 use rustc::mir::interpret::{
17     GlobalId, Scalar, Pointer, FrameInfo, AllocId,
18     InterpResult, truncate, sign_extend,
19 };
20 use rustc_data_structures::fx::FxHashMap;
21
22 use super::{
23     Immediate, Operand, MemPlace, MPlaceTy, Place, PlaceTy, ScalarMaybeUndef,
24     Memory, Machine, PointerArithmetic, FnVal, StackPopInfo
25 };
26
27 pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
28     /// Stores the `Machine` instance.
29     pub machine: M,
30
31     /// The results of the type checker, from rustc.
32     pub tcx: TyCtxtAt<'tcx>,
33
34     /// Bounds in scope for polymorphic evaluations.
35     pub(crate) param_env: ty::ParamEnv<'tcx>,
36
37     /// The virtual memory system.
38     pub memory: Memory<'mir, 'tcx, M>,
39
40     /// The virtual call stack.
41     pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>>,
42
43     /// A cache for deduplicating vtables
44     pub(super) vtables:
45         FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Pointer<M::PointerTag>>,
46 }
47
48 /// A stack frame.
49 #[derive(Clone)]
50 pub struct Frame<'mir, 'tcx, Tag=(), Extra=()> {
51     ////////////////////////////////////////////////////////////////////////////////
52     // Function and callsite information
53     ////////////////////////////////////////////////////////////////////////////////
54     /// The MIR for the function called on this frame.
55     pub body: &'mir mir::Body<'tcx>,
56
57     /// The def_id and substs of the current function.
58     pub instance: ty::Instance<'tcx>,
59
60     /// The span of the call site.
61     pub span: source_map::Span,
62
63     /// Extra data for the machine.
64     pub extra: Extra,
65
66     ////////////////////////////////////////////////////////////////////////////////
67     // Return place and locals
68     ////////////////////////////////////////////////////////////////////////////////
69     /// Work to perform when returning from this function.
70     pub return_to_block: StackPopCleanup,
71
72     /// The location where the result of the current stack frame should be written to,
73     /// and its layout in the caller.
74     pub return_place: Option<PlaceTy<'tcx, Tag>>,
75
76     /// The list of locals for this stack frame, stored in order as
77     /// `[return_ptr, arguments..., variables..., temporaries...]`.
78     /// The locals are stored as `Option<Value>`s.
79     /// `None` represents a local that is currently dead, while a live local
80     /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
81     pub locals: IndexVec<mir::Local, LocalState<'tcx, Tag>>,
82
83     ////////////////////////////////////////////////////////////////////////////////
84     // Current position within the function
85     ////////////////////////////////////////////////////////////////////////////////
86     /// The block that is currently executed (or will be executed after the above call stacks
87     /// return).
88     /// If this is `None`, we are unwinding and this function doesn't need any clean-up.
89     /// Just continue the same as with
90     pub block: Option<mir::BasicBlock>,
91
92     /// The index of the currently evaluated statement.
93     pub stmt: usize,
94 }
95
96 #[derive(Clone, Eq, PartialEq, Debug)] // Miri debug-prints these
97 pub enum StackPopCleanup {
98     /// Jump to the next block in the caller, or cause UB if None (that's a function
99     /// that may never return). Also store layout of return place so
100     /// we can validate it at that layout.
101     /// `ret` stores the block we jump to on a normal return, while 'unwind'
102     /// stores the block used for cleanup during unwinding
103     Goto { ret: Option<mir::BasicBlock>, unwind: Option<mir::BasicBlock> },
104     /// Just do nohing: Used by Main and for the box_alloc hook in miri.
105     /// `cleanup` says whether locals are deallocated. Static computation
106     /// wants them leaked to intern what they need (and just throw away
107     /// the entire `ecx` when it is done).
108     None { cleanup: bool },
109 }
110
111 /// State of a local variable including a memoized layout
112 #[derive(Clone, PartialEq, Eq)]
113 pub struct LocalState<'tcx, Tag=(), Id=AllocId> {
114     pub value: LocalValue<Tag, Id>,
115     /// Don't modify if `Some`, this is only used to prevent computing the layout twice
116     pub layout: Cell<Option<TyLayout<'tcx>>>,
117 }
118
119 /// Current value of a local variable
120 #[derive(Clone, PartialEq, Eq, Debug)] // Miri debug-prints these
121 pub enum LocalValue<Tag=(), Id=AllocId> {
122     /// This local is not currently alive, and cannot be used at all.
123     Dead,
124     /// This local is alive but not yet initialized. It can be written to
125     /// but not read from or its address taken. Locals get initialized on
126     /// first write because for unsized locals, we do not know their size
127     /// before that.
128     Uninitialized,
129     /// A normal, live local.
130     /// Mostly for convenience, we re-use the `Operand` type here.
131     /// This is an optimization over just always having a pointer here;
132     /// we can thus avoid doing an allocation when the local just stores
133     /// immediate values *and* never has its address taken.
134     Live(Operand<Tag, Id>),
135 }
136
137 impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> {
138     pub fn access(&self) -> InterpResult<'tcx, Operand<Tag>> {
139         match self.value {
140             LocalValue::Dead => throw_unsup!(DeadLocal),
141             LocalValue::Uninitialized =>
142                 bug!("The type checker should prevent reading from a never-written local"),
143             LocalValue::Live(val) => Ok(val),
144         }
145     }
146
147     /// Overwrite the local.  If the local can be overwritten in place, return a reference
148     /// to do so; otherwise return the `MemPlace` to consult instead.
149     pub fn access_mut(
150         &mut self,
151     ) -> InterpResult<'tcx, Result<&mut LocalValue<Tag>, MemPlace<Tag>>> {
152         match self.value {
153             LocalValue::Dead => throw_unsup!(DeadLocal),
154             LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)),
155             ref mut local @ LocalValue::Live(Operand::Immediate(_)) |
156             ref mut local @ LocalValue::Uninitialized => {
157                 Ok(Ok(local))
158             }
159         }
160     }
161 }
162
163 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M> {
164     #[inline]
165     fn data_layout(&self) -> &layout::TargetDataLayout {
166         &self.tcx.data_layout
167     }
168 }
169
170 impl<'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpCx<'mir, 'tcx, M>
171 where
172     M: Machine<'mir, 'tcx>,
173 {
174     #[inline]
175     fn tcx(&self) -> TyCtxt<'tcx> {
176         *self.tcx
177     }
178 }
179
180 impl<'mir, 'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'mir, 'tcx, M>
181 where
182     M: Machine<'mir, 'tcx>,
183 {
184     fn param_env(&self) -> ty::ParamEnv<'tcx> {
185         self.param_env
186     }
187 }
188
189 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> {
190     type Ty = Ty<'tcx>;
191     type TyLayout = InterpResult<'tcx, TyLayout<'tcx>>;
192
193     #[inline]
194     fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
195         self.tcx
196             .layout_of(self.param_env.and(ty))
197             .map_err(|layout| err_inval!(Layout(layout)).into())
198     }
199 }
200
201 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
202     pub fn new(
203         tcx: TyCtxtAt<'tcx>,
204         param_env: ty::ParamEnv<'tcx>,
205         machine: M,
206         memory_extra: M::MemoryExtra,
207     ) -> Self {
208         InterpCx {
209             machine,
210             tcx,
211             param_env,
212             memory: Memory::new(tcx, memory_extra),
213             stack: Vec::new(),
214             vtables: FxHashMap::default(),
215         }
216     }
217
218     #[inline(always)]
219     pub fn force_ptr(
220         &self,
221         scalar: Scalar<M::PointerTag>,
222     ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
223         self.memory.force_ptr(scalar)
224     }
225
226     #[inline(always)]
227     pub fn force_bits(
228         &self,
229         scalar: Scalar<M::PointerTag>,
230         size: Size
231     ) -> InterpResult<'tcx, u128> {
232         self.memory.force_bits(scalar, size)
233     }
234
235     #[inline(always)]
236     pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer<M::PointerTag> {
237         self.memory.tag_static_base_pointer(ptr)
238     }
239
240     #[inline(always)]
241     pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] {
242         &self.stack
243     }
244
245     #[inline(always)]
246     pub fn cur_frame(&self) -> usize {
247         assert!(self.stack.len() > 0);
248         self.stack.len() - 1
249     }
250
251     #[inline(always)]
252     pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
253         self.stack.last().expect("no call frames exist")
254     }
255
256     #[inline(always)]
257     pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
258         self.stack.last_mut().expect("no call frames exist")
259     }
260
261     #[inline(always)]
262     pub(super) fn body(&self) -> &'mir mir::Body<'tcx> {
263         self.frame().body
264     }
265
266     #[inline(always)]
267     pub fn sign_extend(&self, value: u128, ty: TyLayout<'_>) -> u128 {
268         assert!(ty.abi.is_signed());
269         sign_extend(value, ty.size)
270     }
271
272     #[inline(always)]
273     pub fn truncate(&self, value: u128, ty: TyLayout<'_>) -> u128 {
274         truncate(value, ty.size)
275     }
276
277     #[inline]
278     pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
279         ty.is_sized(self.tcx, self.param_env)
280     }
281
282     #[inline]
283     pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
284         ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP)
285     }
286
287     pub fn load_mir(
288         &self,
289         instance: ty::InstanceDef<'tcx>,
290         promoted: Option<mir::Promoted>,
291     ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
292         // do not continue if typeck errors occurred (can only occur in local crate)
293         let did = instance.def_id();
294         if did.is_local()
295             && self.tcx.has_typeck_tables(did)
296             && self.tcx.typeck_tables_of(did).tainted_by_errors
297         {
298             throw_inval!(TypeckError)
299         }
300         trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
301         if let Some(promoted) = promoted {
302             return Ok(&self.tcx.promoted_mir(did)[promoted]);
303         }
304         match instance {
305             ty::InstanceDef::Item(def_id) => if self.tcx.is_mir_available(did) {
306                 Ok(self.tcx.optimized_mir(did))
307             } else {
308                 throw_unsup!(NoMirFor(self.tcx.def_path_str(def_id)))
309             },
310             _ => Ok(self.tcx.instance_mir(instance)),
311         }
312     }
313
314     /// Call this on things you got out of the MIR (so it is as generic as the current
315     /// stack frame), to bring it into the proper environment for this interpreter.
316     pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
317         &self,
318         value: T,
319     ) -> T {
320         self.tcx.subst_and_normalize_erasing_regions(
321             self.frame().instance.substs,
322             self.param_env,
323             &value,
324         )
325     }
326
327     /// The `substs` are assumed to already be in our interpreter "universe" (param_env).
328     pub(super) fn resolve(
329         &self,
330         def_id: DefId,
331         substs: SubstsRef<'tcx>
332     ) -> InterpResult<'tcx, ty::Instance<'tcx>> {
333         trace!("resolve: {:?}, {:#?}", def_id, substs);
334         trace!("param_env: {:#?}", self.param_env);
335         trace!("substs: {:#?}", substs);
336         ty::Instance::resolve(
337             *self.tcx,
338             self.param_env,
339             def_id,
340             substs,
341         ).ok_or_else(|| err_inval!(TooGeneric).into())
342     }
343
344     pub fn layout_of_local(
345         &self,
346         frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
347         local: mir::Local,
348         layout: Option<TyLayout<'tcx>>,
349     ) -> InterpResult<'tcx, TyLayout<'tcx>> {
350         // `const_prop` runs into this with an invalid (empty) frame, so we
351         // have to support that case (mostly by skipping all caching).
352         match frame.locals.get(local).and_then(|state| state.layout.get()) {
353             None => {
354                 let layout = crate::interpret::operand::from_known_layout(layout, || {
355                     let local_ty = frame.body.local_decls[local].ty;
356                     let local_ty = self.tcx.subst_and_normalize_erasing_regions(
357                         frame.instance.substs,
358                         self.param_env,
359                         &local_ty,
360                     );
361                     self.layout_of(local_ty)
362                 })?;
363                 if let Some(state) = frame.locals.get(local) {
364                     // Layouts of locals are requested a lot, so we cache them.
365                     state.layout.set(Some(layout));
366                 }
367                 Ok(layout)
368             }
369             Some(layout) => Ok(layout),
370         }
371     }
372
373     /// Returns the actual dynamic size and alignment of the place at the given type.
374     /// Only the "meta" (metadata) part of the place matters.
375     /// This can fail to provide an answer for extern types.
376     pub(super) fn size_and_align_of(
377         &self,
378         metadata: Option<Scalar<M::PointerTag>>,
379         layout: TyLayout<'tcx>,
380     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
381         if !layout.is_unsized() {
382             return Ok(Some((layout.size, layout.align.abi)));
383         }
384         match layout.ty.kind {
385             ty::Adt(..) | ty::Tuple(..) => {
386                 // First get the size of all statically known fields.
387                 // Don't use type_of::sizing_type_of because that expects t to be sized,
388                 // and it also rounds up to alignment, which we want to avoid,
389                 // as the unsized field's alignment could be smaller.
390                 assert!(!layout.ty.is_simd());
391                 trace!("DST layout: {:?}", layout);
392
393                 let sized_size = layout.fields.offset(layout.fields.count() - 1);
394                 let sized_align = layout.align.abi;
395                 trace!(
396                     "DST {} statically sized prefix size: {:?} align: {:?}",
397                     layout.ty,
398                     sized_size,
399                     sized_align
400                 );
401
402                 // Recurse to get the size of the dynamically sized field (must be
403                 // the last field).  Can't have foreign types here, how would we
404                 // adjust alignment and size for them?
405                 let field = layout.field(self, layout.fields.count() - 1)?;
406                 let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? {
407                     Some(size_and_align) => size_and_align,
408                     None => {
409                         // A field with extern type.  If this field is at offset 0, we behave
410                         // like the underlying extern type.
411                         // FIXME: Once we have made decisions for how to handle size and alignment
412                         // of `extern type`, this should be adapted.  It is just a temporary hack
413                         // to get some code to work that probably ought to work.
414                         if sized_size == Size::ZERO {
415                             return Ok(None)
416                         } else {
417                             bug!("Fields cannot be extern types, unless they are at offset 0")
418                         }
419                     }
420                 };
421
422                 // FIXME (#26403, #27023): We should be adding padding
423                 // to `sized_size` (to accommodate the `unsized_align`
424                 // required of the unsized field that follows) before
425                 // summing it with `sized_size`. (Note that since #26403
426                 // is unfixed, we do not yet add the necessary padding
427                 // here. But this is where the add would go.)
428
429                 // Return the sum of sizes and max of aligns.
430                 let size = sized_size + unsized_size;
431
432                 // Choose max of two known alignments (combined value must
433                 // be aligned according to more restrictive of the two).
434                 let align = sized_align.max(unsized_align);
435
436                 // Issue #27023: must add any necessary padding to `size`
437                 // (to make it a multiple of `align`) before returning it.
438                 let size = size.align_to(align);
439
440                 // Check if this brought us over the size limit.
441                 if size.bytes() >= self.tcx.data_layout().obj_size_bound() {
442                     throw_ub_format!("wide pointer metadata contains invalid information: \
443                         total size is bigger than largest supported object");
444                 }
445                 Ok(Some((size, align)))
446             }
447             ty::Dynamic(..) => {
448                 let vtable = metadata.expect("dyn trait fat ptr must have vtable");
449                 // Read size and align from vtable (already checks size).
450                 Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
451             }
452
453             ty::Slice(_) | ty::Str => {
454                 let len = metadata.expect("slice fat ptr must have length").to_machine_usize(self)?;
455                 let elem = layout.field(self, 0)?;
456
457                 // Make sure the slice is not too big.
458                 let size = elem.size.checked_mul(len, &*self.tcx)
459                     .ok_or_else(|| err_ub_format!("invalid slice: \
460                         total size is bigger than largest supported object"))?;
461                 Ok(Some((size, elem.align.abi)))
462             }
463
464             ty::Foreign(_) => {
465                 Ok(None)
466             }
467
468             _ => bug!("size_and_align_of::<{:?}> not supported", layout.ty),
469         }
470     }
471     #[inline]
472     pub fn size_and_align_of_mplace(
473         &self,
474         mplace: MPlaceTy<'tcx, M::PointerTag>
475     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
476         self.size_and_align_of(mplace.meta, mplace.layout)
477     }
478
479     pub fn push_stack_frame(
480         &mut self,
481         instance: ty::Instance<'tcx>,
482         span: Span,
483         body: &'mir mir::Body<'tcx>,
484         return_place: Option<PlaceTy<'tcx, M::PointerTag>>,
485         return_to_block: StackPopCleanup,
486     ) -> InterpResult<'tcx> {
487         if self.stack.len() > 0 {
488             info!("PAUSING({}) {}", self.cur_frame(), self.frame().instance);
489         }
490         ::log_settings::settings().indentation += 1;
491
492         // first push a stack frame so we have access to the local substs
493         let extra = M::stack_push(self)?;
494         self.stack.push(Frame {
495             body,
496             block: Some(mir::START_BLOCK),
497             return_to_block,
498             return_place,
499             // empty local array, we fill it in below, after we are inside the stack frame and
500             // all methods actually know about the frame
501             locals: IndexVec::new(),
502             span,
503             instance,
504             stmt: 0,
505             extra,
506         });
507
508         // don't allocate at all for trivial constants
509         if body.local_decls.len() > 1 {
510             // Locals are initially uninitialized.
511             let dummy = LocalState {
512                 value: LocalValue::Uninitialized,
513                 layout: Cell::new(None),
514             };
515             let mut locals = IndexVec::from_elem(dummy, &body.local_decls);
516             // Return place is handled specially by the `eval_place` functions, and the
517             // entry in `locals` should never be used. Make it dead, to be sure.
518             locals[mir::RETURN_PLACE].value = LocalValue::Dead;
519             // Now mark those locals as dead that we do not want to initialize
520             match self.tcx.def_kind(instance.def_id()) {
521                 // statics and constants don't have `Storage*` statements, no need to look for them
522                 Some(DefKind::Static)
523                 | Some(DefKind::Const)
524                 | Some(DefKind::AssocConst) => {},
525                 _ => {
526                     trace!("push_stack_frame: {:?}: num_bbs: {}", span, body.basic_blocks().len());
527                     for block in body.basic_blocks() {
528                         for stmt in block.statements.iter() {
529                             use rustc::mir::StatementKind::{StorageDead, StorageLive};
530                             match stmt.kind {
531                                 StorageLive(local) |
532                                 StorageDead(local) => {
533                                     locals[local].value = LocalValue::Dead;
534                                 }
535                                 _ => {}
536                             }
537                         }
538                     }
539                 },
540             }
541             // done
542             self.frame_mut().locals = locals;
543         }
544
545         info!("ENTERING({}) {}", self.cur_frame(), self.frame().instance);
546
547         if self.stack.len() > self.tcx.sess.const_eval_stack_frame_limit {
548             throw_exhaust!(StackFrameLimitReached)
549         } else {
550             Ok(())
551         }
552     }
553
554     pub(super) fn pop_stack_frame(
555         &mut self,
556         unwinding: bool
557     ) -> InterpResult<'tcx> {
558         info!("LEAVING({}) {} (unwinding = {})",
559             self.cur_frame(), self.frame().instance, unwinding);
560
561         // Sanity check `unwinding`.
562         assert_eq!(
563             unwinding,
564             match self.frame().block {
565                 None => true,
566                 Some(block) => self.body().basic_blocks()[block].is_cleanup
567             }
568         );
569
570         ::log_settings::settings().indentation -= 1;
571         let frame = self.stack.pop().expect(
572             "tried to pop a stack frame, but there were none",
573         );
574         let stack_pop_info = M::stack_pop(self, frame.extra)?;
575         match (unwinding, stack_pop_info) {
576             (true, StackPopInfo::StartUnwinding) =>
577                 bug!("Attempted to start unwinding while already unwinding!"),
578             (false, StackPopInfo::StopUnwinding) =>
579                 bug!("Attempted to stop unwinding while there is no unwinding!"),
580             _ => {}
581         }
582
583         // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
584         // In that case, we return early. We also avoid validation in that case,
585         // because this is CTFE and the final value will be thoroughly validated anyway.
586         let cleanup = unwinding || match frame.return_to_block {
587             StackPopCleanup::Goto{ .. } => true,
588             StackPopCleanup::None { cleanup, .. } => {
589                 cleanup
590             }
591         };
592         if !cleanup {
593             assert!(self.stack.is_empty(), "only the topmost frame should ever be leaked");
594             // Leak the locals, skip validation.
595             return Ok(());
596         }
597
598         // Cleanup: deallocate all locals that are backed by an allocation.
599         for local in frame.locals {
600             self.deallocate_local(local.value)?;
601         }
602
603         // Now where do we jump next?
604
605         // Determine if we leave this function normally or via unwinding.
606         let cur_unwinding = unwinding && stack_pop_info != StackPopInfo::StopUnwinding;
607         trace!("StackPopCleanup: {:?} StackPopInfo: {:?} cur_unwinding = {:?}",
608                frame.return_to_block, stack_pop_info, cur_unwinding);
609         if cur_unwinding {
610             // Follow the unwind edge.
611             match frame.return_to_block {
612                 StackPopCleanup::Goto { unwind, .. } => {
613                     let next_frame = self.frame_mut();
614                     // If `unwind` is `None`, we'll leave that function immediately again.
615                     next_frame.block = unwind;
616                     next_frame.stmt = 0;
617                 },
618                 StackPopCleanup::None { .. } =>
619                     bug!("Encountered StackPopCleanup::None while unwinding"),
620             }
621         } else {
622             // Follow the normal return edge.
623             // Validate the return value. Do this after deallocating so that we catch dangling
624             // references.
625             if let Some(return_place) = frame.return_place {
626                 if M::enforce_validity(self) {
627                     // Data got changed, better make sure it matches the type!
628                     // It is still possible that the return place held invalid data while
629                     // the function is running, but that's okay because nobody could have
630                     // accessed that same data from the "outside" to observe any broken
631                     // invariant -- that is, unless a function somehow has a ptr to
632                     // its return place... but the way MIR is currently generated, the
633                     // return place is always a local and then this cannot happen.
634                     self.validate_operand(
635                         self.place_to_op(return_place)?,
636                         vec![],
637                         None,
638                     )?;
639                 }
640             } else {
641                 // Uh, that shouldn't happen... the function did not intend to return
642                 throw_ub!(Unreachable);
643             }
644
645             // Jump to new block -- *after* validation so that the spans make more sense.
646             match frame.return_to_block {
647                 StackPopCleanup::Goto { ret, ..  } => {
648                     self.goto_block(ret)?;
649                 }
650                 StackPopCleanup::None { .. } => {}
651             }
652         }
653
654         if self.stack.len() > 0 {
655             info!("CONTINUING({}) {} (unwinding = {})",
656                 self.cur_frame(), self.frame().instance, cur_unwinding);
657         }
658
659         Ok(())
660     }
661
662     /// Mark a storage as live, killing the previous content and returning it.
663     /// Remember to deallocate that!
664     pub fn storage_live(
665         &mut self,
666         local: mir::Local
667     ) -> InterpResult<'tcx, LocalValue<M::PointerTag>> {
668         assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
669         trace!("{:?} is now live", local);
670
671         let local_val = LocalValue::Uninitialized;
672         // StorageLive *always* kills the value that's currently stored.
673         // However, we do not error if the variable already is live;
674         // see <https://github.com/rust-lang/rust/issues/42371>.
675         Ok(mem::replace(&mut self.frame_mut().locals[local].value, local_val))
676     }
677
678     /// Returns the old value of the local.
679     /// Remember to deallocate that!
680     pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue<M::PointerTag> {
681         assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
682         trace!("{:?} is now dead", local);
683
684         mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead)
685     }
686
687     pub(super) fn deallocate_local(
688         &mut self,
689         local: LocalValue<M::PointerTag>,
690     ) -> InterpResult<'tcx> {
691         // FIXME: should we tell the user that there was a local which was never written to?
692         if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
693             trace!("deallocating local");
694             let ptr = ptr.to_ptr()?;
695             self.memory.dump_alloc(ptr.alloc_id);
696             self.memory.deallocate_local(ptr)?;
697         };
698         Ok(())
699     }
700
701     pub fn const_eval_raw(
702         &self,
703         gid: GlobalId<'tcx>,
704     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
705         // FIXME(oli-obk): make this check an assertion that it's not a static here
706         // FIXME(RalfJ, oli-obk): document that `Place::Static` can never be anything but a static
707         // and `ConstValue::Unevaluated` can never be a static
708         let param_env = if self.tcx.is_static(gid.instance.def_id()) {
709             ty::ParamEnv::reveal_all()
710         } else {
711             self.param_env
712         };
713         // We use `const_eval_raw` here, and get an unvalidated result.  That is okay:
714         // Our result will later be validated anyway, and there seems no good reason
715         // to have to fail early here.  This is also more consistent with
716         // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
717         let val = self.tcx.const_eval_raw(param_env.and(gid))?;
718         self.raw_const_to_mplace(val)
719     }
720
721     pub fn dump_place(&self, place: Place<M::PointerTag>) {
722         // Debug output
723         if !log_enabled!(::log::Level::Trace) {
724             return;
725         }
726         match place {
727             Place::Local { frame, local } => {
728                 let mut allocs = Vec::new();
729                 let mut msg = format!("{:?}", local);
730                 if frame != self.cur_frame() {
731                     write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap();
732                 }
733                 write!(msg, ":").unwrap();
734
735                 match self.stack[frame].locals[local].value {
736                     LocalValue::Dead => write!(msg, " is dead").unwrap(),
737                     LocalValue::Uninitialized => write!(msg, " is uninitialized").unwrap(),
738                     LocalValue::Live(Operand::Indirect(mplace)) => {
739                         match mplace.ptr {
740                             Scalar::Ptr(ptr) => {
741                                 write!(msg, " by align({}){} ref:",
742                                     mplace.align.bytes(),
743                                     match mplace.meta {
744                                         Some(meta) => format!(" meta({:?})", meta),
745                                         None => String::new()
746                                     }
747                                 ).unwrap();
748                                 allocs.push(ptr.alloc_id);
749                             }
750                             ptr => write!(msg, " by integral ref: {:?}", ptr).unwrap(),
751                         }
752                     }
753                     LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
754                         write!(msg, " {:?}", val).unwrap();
755                         if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val {
756                             allocs.push(ptr.alloc_id);
757                         }
758                     }
759                     LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
760                         write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
761                         if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val1 {
762                             allocs.push(ptr.alloc_id);
763                         }
764                         if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val2 {
765                             allocs.push(ptr.alloc_id);
766                         }
767                     }
768                 }
769
770                 trace!("{}", msg);
771                 self.memory.dump_allocs(allocs);
772             }
773             Place::Ptr(mplace) => {
774                 match mplace.ptr {
775                     Scalar::Ptr(ptr) => {
776                         trace!("by align({}) ref:", mplace.align.bytes());
777                         self.memory.dump_alloc(ptr.alloc_id);
778                     }
779                     ptr => trace!(" integral by ref: {:?}", ptr),
780                 }
781             }
782         }
783     }
784
785     pub fn generate_stacktrace(&self, explicit_span: Option<Span>) -> Vec<FrameInfo<'tcx>> {
786         let mut last_span = None;
787         let mut frames = Vec::new();
788         for &Frame { instance, span, body, block, stmt, .. } in self.stack().iter().rev() {
789             // make sure we don't emit frames that are duplicates of the previous
790             if explicit_span == Some(span) {
791                 last_span = Some(span);
792                 continue;
793             }
794             if let Some(last) = last_span {
795                 if last == span {
796                     continue;
797                 }
798             } else {
799                 last_span = Some(span);
800             }
801
802             let lint_root = block.and_then(|block| {
803                 let block = &body.basic_blocks()[block];
804                 let source_info = if stmt < block.statements.len() {
805                     block.statements[stmt].source_info
806                 } else {
807                     block.terminator().source_info
808                 };
809                 match body.source_scope_local_data {
810                     mir::ClearCrossCrate::Set(ref ivs) => Some(ivs[source_info.scope].lint_root),
811                     mir::ClearCrossCrate::Clear => None,
812                 }
813             });
814
815             frames.push(FrameInfo { call_site: span, instance, lint_root });
816         }
817         trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span);
818         frames
819     }
820
821     /// Resolve the function at the specified slot in the provided
822     /// vtable. An index of '0' corresponds to the first method
823     /// declared in the trait of the provided vtable
824     pub fn get_vtable_slot(
825         &self,
826         vtable: Scalar<M::PointerTag>,
827         idx: usize
828     ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
829         let ptr_size = self.pointer_size();
830         // Skip over the 'drop_ptr', 'size', and 'align' fields
831         let vtable_slot = vtable.ptr_offset(ptr_size * (idx as u64 + 3), self)?;
832         let vtable_slot = self.memory.check_ptr_access(
833             vtable_slot,
834             ptr_size,
835             self.tcx.data_layout.pointer_align.abi,
836         )?.expect("cannot be a ZST");
837         let fn_ptr = self.memory.get(vtable_slot.alloc_id)?
838             .read_ptr_sized(self, vtable_slot)?.not_undef()?;
839         Ok(self.memory.get_fn(fn_ptr)?)
840     }
841 }