]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/eval_context.rs
fix rustfmt fallout
[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 rustc::ich::StableHashingContext;
6 use rustc::mir;
7 use rustc::mir::interpret::{
8     sign_extend, truncate, AllocId, FrameInfo, GlobalId, InterpResult, Pointer, Scalar,
9 };
10 use rustc::ty::layout::{self, Align, HasDataLayout, LayoutOf, Size, TyLayout};
11 use rustc::ty::query::TyCtxtAt;
12 use rustc::ty::subst::SubstsRef;
13 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
14 use rustc_data_structures::fx::FxHashMap;
15 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
16 use rustc_hir::def::DefKind;
17 use rustc_hir::def_id::DefId;
18 use rustc_index::vec::IndexVec;
19 use rustc_macros::HashStable;
20 use rustc_span::source_map::{self, Span, DUMMY_SP};
21
22 use super::{
23     Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy,
24     ScalarMaybeUndef, 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 `Resume`.
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, HashStable)] // 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, HashStable)]
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     #[stable_hasher(ignore)]
117     pub layout: Cell<Option<TyLayout<'tcx>>>,
118 }
119
120 /// Current value of a local variable
121 #[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable)] // Miri debug-prints these
122 pub enum LocalValue<Tag = (), Id = AllocId> {
123     /// This local is not currently alive, and cannot be used at all.
124     Dead,
125     /// This local is alive but not yet initialized. It can be written to
126     /// but not read from or its address taken. Locals get initialized on
127     /// first write because for unsized locals, we do not know their size
128     /// before that.
129     Uninitialized,
130     /// A normal, live local.
131     /// Mostly for convenience, we re-use the `Operand` type here.
132     /// This is an optimization over just always having a pointer here;
133     /// we can thus avoid doing an allocation when the local just stores
134     /// immediate values *and* never has its address taken.
135     Live(Operand<Tag, Id>),
136 }
137
138 impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> {
139     pub fn access(&self) -> InterpResult<'tcx, Operand<Tag>> {
140         match self.value {
141             LocalValue::Dead => throw_unsup!(DeadLocal),
142             LocalValue::Uninitialized => {
143                 bug!("The type checker should prevent reading from a never-written local")
144             }
145             LocalValue::Live(val) => Ok(val),
146         }
147     }
148
149     /// Overwrite the local.  If the local can be overwritten in place, return a reference
150     /// to do so; otherwise return the `MemPlace` to consult instead.
151     pub fn access_mut(
152         &mut self,
153     ) -> InterpResult<'tcx, Result<&mut LocalValue<Tag>, MemPlace<Tag>>> {
154         match self.value {
155             LocalValue::Dead => {
156                 throw_unsup!(DeadLocal)
157             }
158             LocalValue::Live(Operand::Indirect(mplace)) => {
159                 Ok(Err(mplace))
160             }
161             ref mut local @ LocalValue::Live(Operand::Immediate(_))
162             | ref mut local @ LocalValue::Uninitialized => {
163                 Ok(Ok(local))
164             }
165         }
166     }
167 }
168
169 impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> {
170     /// Return the `SourceInfo` of the current instruction.
171     pub fn current_source_info(&self) -> Option<mir::SourceInfo> {
172         self.block.map(|block| {
173             let block = &self.body.basic_blocks()[block];
174             if self.stmt < block.statements.len() {
175                 block.statements[self.stmt].source_info
176             } else {
177                 block.terminator().source_info
178             }
179         })
180     }
181 }
182
183 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M> {
184     #[inline]
185     fn data_layout(&self) -> &layout::TargetDataLayout {
186         &self.tcx.data_layout
187     }
188 }
189
190 impl<'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpCx<'mir, 'tcx, M>
191 where
192     M: Machine<'mir, 'tcx>,
193 {
194     #[inline]
195     fn tcx(&self) -> TyCtxt<'tcx> {
196         *self.tcx
197     }
198 }
199
200 impl<'mir, 'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'mir, 'tcx, M>
201 where
202     M: Machine<'mir, 'tcx>,
203 {
204     fn param_env(&self) -> ty::ParamEnv<'tcx> {
205         self.param_env
206     }
207 }
208
209 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> {
210     type Ty = Ty<'tcx>;
211     type TyLayout = InterpResult<'tcx, TyLayout<'tcx>>;
212
213     #[inline]
214     fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
215         self.tcx
216             .layout_of(self.param_env.and(ty))
217             .map_err(|layout| err_inval!(Layout(layout)).into())
218     }
219 }
220
221 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
222     pub fn new(
223         tcx: TyCtxtAt<'tcx>,
224         param_env: ty::ParamEnv<'tcx>,
225         machine: M,
226         memory_extra: M::MemoryExtra,
227     ) -> Self {
228         InterpCx {
229             machine,
230             tcx,
231             param_env,
232             memory: Memory::new(tcx, memory_extra),
233             stack: Vec::new(),
234             vtables: FxHashMap::default(),
235         }
236     }
237
238     #[inline(always)]
239     pub fn force_ptr(
240         &self,
241         scalar: Scalar<M::PointerTag>,
242     ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
243         self.memory.force_ptr(scalar)
244     }
245
246     #[inline(always)]
247     pub fn force_bits(
248         &self,
249         scalar: Scalar<M::PointerTag>,
250         size: Size,
251     ) -> InterpResult<'tcx, u128> {
252         self.memory.force_bits(scalar, size)
253     }
254
255     /// Call this to turn untagged "global" pointers (obtained via `tcx`) into
256     /// the *canonical* machine pointer to the allocation.  Must never be used
257     /// for any other pointers!
258     ///
259     /// This represents a *direct* access to that memory, as opposed to access
260     /// through a pointer that was created by the program.
261     #[inline(always)]
262     pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer<M::PointerTag> {
263         self.memory.tag_static_base_pointer(ptr)
264     }
265
266     #[inline(always)]
267     pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] {
268         &self.stack
269     }
270
271     #[inline(always)]
272     pub fn cur_frame(&self) -> usize {
273         assert!(self.stack.len() > 0);
274         self.stack.len() - 1
275     }
276
277     #[inline(always)]
278     pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
279         self.stack.last().expect("no call frames exist")
280     }
281
282     #[inline(always)]
283     pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
284         self.stack.last_mut().expect("no call frames exist")
285     }
286
287     #[inline(always)]
288     pub(super) fn body(&self) -> &'mir mir::Body<'tcx> {
289         self.frame().body
290     }
291
292     #[inline(always)]
293     pub fn sign_extend(&self, value: u128, ty: TyLayout<'_>) -> u128 {
294         assert!(ty.abi.is_signed());
295         sign_extend(value, ty.size)
296     }
297
298     #[inline(always)]
299     pub fn truncate(&self, value: u128, ty: TyLayout<'_>) -> u128 {
300         truncate(value, ty.size)
301     }
302
303     #[inline]
304     pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
305         ty.is_sized(self.tcx, self.param_env)
306     }
307
308     #[inline]
309     pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
310         ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP)
311     }
312
313     pub fn load_mir(
314         &self,
315         instance: ty::InstanceDef<'tcx>,
316         promoted: Option<mir::Promoted>,
317     ) -> InterpResult<'tcx, mir::ReadOnlyBodyAndCache<'tcx, 'tcx>> {
318         // do not continue if typeck errors occurred (can only occur in local crate)
319         let did = instance.def_id();
320         if did.is_local()
321             && self.tcx.has_typeck_tables(did)
322             && self.tcx.typeck_tables_of(did).tainted_by_errors
323         {
324             throw_inval!(TypeckError)
325         }
326         trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
327         if let Some(promoted) = promoted {
328             return Ok(self.tcx.promoted_mir(did)[promoted].unwrap_read_only());
329         }
330         match instance {
331             ty::InstanceDef::Item(def_id) => {
332                 if self.tcx.is_mir_available(did) {
333                     Ok(self.tcx.optimized_mir(did).unwrap_read_only())
334                 } else {
335                     throw_unsup!(NoMirFor(self.tcx.def_path_str(def_id)))
336                 }
337             }
338             _ => Ok(self.tcx.instance_mir(instance)),
339         }
340     }
341
342     /// Call this on things you got out of the MIR (so it is as generic as the current
343     /// stack frame), to bring it into the proper environment for this interpreter.
344     pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
345         &self,
346         value: T,
347     ) -> T {
348         self.tcx.subst_and_normalize_erasing_regions(
349             self.frame().instance.substs,
350             self.param_env,
351             &value,
352         )
353     }
354
355     /// The `substs` are assumed to already be in our interpreter "universe" (param_env).
356     pub(super) fn resolve(
357         &self,
358         def_id: DefId,
359         substs: SubstsRef<'tcx>,
360     ) -> InterpResult<'tcx, ty::Instance<'tcx>> {
361         trace!("resolve: {:?}, {:#?}", def_id, substs);
362         trace!("param_env: {:#?}", self.param_env);
363         trace!("substs: {:#?}", substs);
364         ty::Instance::resolve(*self.tcx, self.param_env, def_id, substs)
365             .ok_or_else(|| err_inval!(TooGeneric).into())
366     }
367
368     pub fn layout_of_local(
369         &self,
370         frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
371         local: mir::Local,
372         layout: Option<TyLayout<'tcx>>,
373     ) -> InterpResult<'tcx, TyLayout<'tcx>> {
374         // `const_prop` runs into this with an invalid (empty) frame, so we
375         // have to support that case (mostly by skipping all caching).
376         match frame.locals.get(local).and_then(|state| state.layout.get()) {
377             None => {
378                 let layout = crate::interpret::operand::from_known_layout(layout, || {
379                     let local_ty = frame.body.local_decls[local].ty;
380                     let local_ty = self.tcx.subst_and_normalize_erasing_regions(
381                         frame.instance.substs,
382                         self.param_env,
383                         &local_ty,
384                     );
385                     self.layout_of(local_ty)
386                 })?;
387                 if let Some(state) = frame.locals.get(local) {
388                     // Layouts of locals are requested a lot, so we cache them.
389                     state.layout.set(Some(layout));
390                 }
391                 Ok(layout)
392             }
393             Some(layout) => Ok(layout),
394         }
395     }
396
397     /// Returns the actual dynamic size and alignment of the place at the given type.
398     /// Only the "meta" (metadata) part of the place matters.
399     /// This can fail to provide an answer for extern types.
400     pub(super) fn size_and_align_of(
401         &self,
402         metadata: MemPlaceMeta<M::PointerTag>,
403         layout: TyLayout<'tcx>,
404     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
405         if !layout.is_unsized() {
406             return Ok(Some((layout.size, layout.align.abi)));
407         }
408         match layout.ty.kind {
409             ty::Adt(..) | ty::Tuple(..) => {
410                 // First get the size of all statically known fields.
411                 // Don't use type_of::sizing_type_of because that expects t to be sized,
412                 // and it also rounds up to alignment, which we want to avoid,
413                 // as the unsized field's alignment could be smaller.
414                 assert!(!layout.ty.is_simd());
415                 trace!("DST layout: {:?}", layout);
416
417                 let sized_size = layout.fields.offset(layout.fields.count() - 1);
418                 let sized_align = layout.align.abi;
419                 trace!(
420                     "DST {} statically sized prefix size: {:?} align: {:?}",
421                     layout.ty,
422                     sized_size,
423                     sized_align
424                 );
425
426                 // Recurse to get the size of the dynamically sized field (must be
427                 // the last field).  Can't have foreign types here, how would we
428                 // adjust alignment and size for them?
429                 let field = layout.field(self, layout.fields.count() - 1)?;
430                 let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? {
431                     Some(size_and_align) => size_and_align,
432                     None => {
433                         // A field with extern type.  If this field is at offset 0, we behave
434                         // like the underlying extern type.
435                         // FIXME: Once we have made decisions for how to handle size and alignment
436                         // of `extern type`, this should be adapted.  It is just a temporary hack
437                         // to get some code to work that probably ought to work.
438                         if sized_size == Size::ZERO {
439                             return Ok(None);
440                         } else {
441                             bug!("Fields cannot be extern types, unless they are at offset 0")
442                         }
443                     }
444                 };
445
446                 // FIXME (#26403, #27023): We should be adding padding
447                 // to `sized_size` (to accommodate the `unsized_align`
448                 // required of the unsized field that follows) before
449                 // summing it with `sized_size`. (Note that since #26403
450                 // is unfixed, we do not yet add the necessary padding
451                 // here. But this is where the add would go.)
452
453                 // Return the sum of sizes and max of aligns.
454                 let size = sized_size + unsized_size;
455
456                 // Choose max of two known alignments (combined value must
457                 // be aligned according to more restrictive of the two).
458                 let align = sized_align.max(unsized_align);
459
460                 // Issue #27023: must add any necessary padding to `size`
461                 // (to make it a multiple of `align`) before returning it.
462                 let size = size.align_to(align);
463
464                 // Check if this brought us over the size limit.
465                 if size.bytes() >= self.tcx.data_layout().obj_size_bound() {
466                     throw_ub_format!(
467                         "wide pointer metadata contains invalid information: \
468                         total size is bigger than largest supported object"
469                     );
470                 }
471                 Ok(Some((size, align)))
472             }
473             ty::Dynamic(..) => {
474                 let vtable = metadata.unwrap_meta();
475                 // Read size and align from vtable (already checks size).
476                 Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
477             }
478
479             ty::Slice(_) | ty::Str => {
480                 let len = metadata.unwrap_meta().to_machine_usize(self)?;
481                 let elem = layout.field(self, 0)?;
482
483                 // Make sure the slice is not too big.
484                 let size = elem.size.checked_mul(len, &*self.tcx).ok_or_else(|| {
485                     err_ub_format!(
486                         "invalid slice: \
487                         total size is bigger than largest supported object"
488                     )
489                 })?;
490                 Ok(Some((size, elem.align.abi)))
491             }
492
493             ty::Foreign(_) => Ok(None),
494
495             _ => bug!("size_and_align_of::<{:?}> not supported", layout.ty),
496         }
497     }
498     #[inline]
499     pub fn size_and_align_of_mplace(
500         &self,
501         mplace: MPlaceTy<'tcx, M::PointerTag>,
502     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
503         self.size_and_align_of(mplace.meta, mplace.layout)
504     }
505
506     pub fn push_stack_frame(
507         &mut self,
508         instance: ty::Instance<'tcx>,
509         span: Span,
510         body: &'mir mir::Body<'tcx>,
511         return_place: Option<PlaceTy<'tcx, M::PointerTag>>,
512         return_to_block: StackPopCleanup,
513     ) -> InterpResult<'tcx> {
514         if self.stack.len() > 0 {
515             info!("PAUSING({}) {}", self.cur_frame(), self.frame().instance);
516         }
517         ::log_settings::settings().indentation += 1;
518
519         // first push a stack frame so we have access to the local substs
520         let extra = M::stack_push(self)?;
521         self.stack.push(Frame {
522             body,
523             block: Some(mir::START_BLOCK),
524             return_to_block,
525             return_place,
526             // empty local array, we fill it in below, after we are inside the stack frame and
527             // all methods actually know about the frame
528             locals: IndexVec::new(),
529             span,
530             instance,
531             stmt: 0,
532             extra,
533         });
534
535         // don't allocate at all for trivial constants
536         if body.local_decls.len() > 1 {
537             // Locals are initially uninitialized.
538             let dummy = LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) };
539             let mut locals = IndexVec::from_elem(dummy, &body.local_decls);
540             // Return place is handled specially by the `eval_place` functions, and the
541             // entry in `locals` should never be used. Make it dead, to be sure.
542             locals[mir::RETURN_PLACE].value = LocalValue::Dead;
543             // Now mark those locals as dead that we do not want to initialize
544             match self.tcx.def_kind(instance.def_id()) {
545                 // statics and constants don't have `Storage*` statements, no need to look for them
546                 Some(DefKind::Static) | Some(DefKind::Const) | Some(DefKind::AssocConst) => {}
547                 _ => {
548                     trace!("push_stack_frame: {:?}: num_bbs: {}", span, body.basic_blocks().len());
549                     for block in body.basic_blocks() {
550                         for stmt in block.statements.iter() {
551                             use rustc::mir::StatementKind::{StorageDead, StorageLive};
552                             match stmt.kind {
553                                 StorageLive(local) | StorageDead(local) => {
554                                     locals[local].value = LocalValue::Dead;
555                                 }
556                                 _ => {}
557                             }
558                         }
559                     }
560                 }
561             }
562             // done
563             self.frame_mut().locals = locals;
564         }
565
566         info!("ENTERING({}) {}", self.cur_frame(), self.frame().instance);
567
568         if self.stack.len() > *self.tcx.sess.recursion_limit.get() {
569             throw_exhaust!(StackFrameLimitReached)
570         } else {
571             Ok(())
572         }
573     }
574
575     /// Jump to the given block.
576     #[inline]
577     pub fn go_to_block(&mut self, target: mir::BasicBlock) {
578         let frame = self.frame_mut();
579         frame.block = Some(target);
580         frame.stmt = 0;
581     }
582
583     /// *Return* to the given `target` basic block.
584     /// Do *not* use for unwinding! Use `unwind_to_block` instead.
585     ///
586     /// If `target` is `None`, that indicates the function cannot return, so we raise UB.
587     pub fn return_to_block(&mut self, target: Option<mir::BasicBlock>) -> InterpResult<'tcx> {
588         if let Some(target) = target {
589             Ok(self.go_to_block(target))
590         } else {
591             throw_ub!(Unreachable)
592         }
593     }
594
595     /// *Unwind* to the given `target` basic block.
596     /// Do *not* use for returning! Use `return_to_block` instead.
597     ///
598     /// If `target` is `None`, that indicates the function does not need cleanup during
599     /// unwinding, and we will just keep propagating that upwards.
600     pub fn unwind_to_block(&mut self, target: Option<mir::BasicBlock>) {
601         let frame = self.frame_mut();
602         frame.block = target;
603         frame.stmt = 0;
604     }
605
606     /// Pops the current frame from the stack, deallocating the
607     /// memory for allocated locals.
608     ///
609     /// If `unwinding` is `false`, then we are performing a normal return
610     /// from a function. In this case, we jump back into the frame of the caller,
611     /// and continue execution as normal.
612     ///
613     /// If `unwinding` is `true`, then we are in the middle of a panic,
614     /// and need to unwind this frame. In this case, we jump to the
615     /// `cleanup` block for the function, which is responsible for running
616     /// `Drop` impls for any locals that have been initialized at this point.
617     /// The cleanup block ends with a special `Resume` terminator, which will
618     /// cause us to continue unwinding.
619     pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx> {
620         info!(
621             "LEAVING({}) {} (unwinding = {})",
622             self.cur_frame(),
623             self.frame().instance,
624             unwinding
625         );
626
627         // Sanity check `unwinding`.
628         assert_eq!(
629             unwinding,
630             match self.frame().block {
631                 None => true,
632                 Some(block) => self.body().basic_blocks()[block].is_cleanup,
633             }
634         );
635
636         ::log_settings::settings().indentation -= 1;
637         let frame = self.stack.pop().expect("tried to pop a stack frame, but there were none");
638         let stack_pop_info = M::stack_pop(self, frame.extra, unwinding)?;
639         if let (false, StackPopInfo::StopUnwinding) = (unwinding, stack_pop_info) {
640             bug!("Attempted to stop unwinding while there is no unwinding!");
641         }
642
643         // Now where do we jump next?
644
645         // Determine if we leave this function normally or via unwinding.
646         let cur_unwinding =
647             if let StackPopInfo::StopUnwinding = stack_pop_info { false } else { unwinding };
648
649         // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
650         // In that case, we return early. We also avoid validation in that case,
651         // because this is CTFE and the final value will be thoroughly validated anyway.
652         let (cleanup, next_block) = match frame.return_to_block {
653             StackPopCleanup::Goto { ret, unwind } => {
654                 (true, Some(if cur_unwinding { unwind } else { ret }))
655             }
656             StackPopCleanup::None { cleanup, .. } => (cleanup, None),
657         };
658
659         if !cleanup {
660             assert!(self.stack.is_empty(), "only the topmost frame should ever be leaked");
661             assert!(next_block.is_none(), "tried to skip cleanup when we have a next block!");
662             // Leak the locals, skip validation.
663             return Ok(());
664         }
665
666         // Cleanup: deallocate all locals that are backed by an allocation.
667         for local in frame.locals {
668             self.deallocate_local(local.value)?;
669         }
670
671         trace!(
672             "StackPopCleanup: {:?} StackPopInfo: {:?} cur_unwinding = {:?}",
673             frame.return_to_block,
674             stack_pop_info,
675             cur_unwinding
676         );
677         if cur_unwinding {
678             // Follow the unwind edge.
679             let unwind = next_block.expect("Encounted StackPopCleanup::None when unwinding!");
680             self.unwind_to_block(unwind);
681         } else {
682             // Follow the normal return edge.
683             // Validate the return value. Do this after deallocating so that we catch dangling
684             // references.
685             if let Some(return_place) = frame.return_place {
686                 if M::enforce_validity(self) {
687                     // Data got changed, better make sure it matches the type!
688                     // It is still possible that the return place held invalid data while
689                     // the function is running, but that's okay because nobody could have
690                     // accessed that same data from the "outside" to observe any broken
691                     // invariant -- that is, unless a function somehow has a ptr to
692                     // its return place... but the way MIR is currently generated, the
693                     // return place is always a local and then this cannot happen.
694                     self.validate_operand(self.place_to_op(return_place)?, vec![], None)?;
695                 }
696             } else {
697                 // Uh, that shouldn't happen... the function did not intend to return
698                 throw_ub!(Unreachable);
699             }
700
701             // Jump to new block -- *after* validation so that the spans make more sense.
702             if let Some(ret) = next_block {
703                 self.return_to_block(ret)?;
704             }
705         }
706
707         if self.stack.len() > 0 {
708             info!(
709                 "CONTINUING({}) {} (unwinding = {})",
710                 self.cur_frame(),
711                 self.frame().instance,
712                 cur_unwinding
713             );
714         }
715
716         Ok(())
717     }
718
719     /// Mark a storage as live, killing the previous content and returning it.
720     /// Remember to deallocate that!
721     pub fn storage_live(
722         &mut self,
723         local: mir::Local,
724     ) -> InterpResult<'tcx, LocalValue<M::PointerTag>> {
725         assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
726         trace!("{:?} is now live", local);
727
728         let local_val = LocalValue::Uninitialized;
729         // StorageLive *always* kills the value that's currently stored.
730         // However, we do not error if the variable already is live;
731         // see <https://github.com/rust-lang/rust/issues/42371>.
732         Ok(mem::replace(&mut self.frame_mut().locals[local].value, local_val))
733     }
734
735     /// Returns the old value of the local.
736     /// Remember to deallocate that!
737     pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue<M::PointerTag> {
738         assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
739         trace!("{:?} is now dead", local);
740
741         mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead)
742     }
743
744     pub(super) fn deallocate_local(
745         &mut self,
746         local: LocalValue<M::PointerTag>,
747     ) -> InterpResult<'tcx> {
748         // FIXME: should we tell the user that there was a local which was never written to?
749         if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
750             trace!("deallocating local");
751             // All locals have a backing allocation, even if the allocation is empty
752             // due to the local having ZST type.
753             let ptr = ptr.assert_ptr();
754             if log_enabled!(::log::Level::Trace) {
755                 self.memory.dump_alloc(ptr.alloc_id);
756             }
757             self.memory.deallocate_local(ptr)?;
758         };
759         Ok(())
760     }
761
762     pub(super) fn const_eval(
763         &self,
764         gid: GlobalId<'tcx>,
765     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
766         // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
767         // and thus don't care about the parameter environment. While we could just use
768         // `self.param_env`, that would mean we invoke the query to evaluate the static
769         // with different parameter environments, thus causing the static to be evaluated
770         // multiple times.
771         let param_env = if self.tcx.is_static(gid.instance.def_id()) {
772             ty::ParamEnv::reveal_all()
773         } else {
774             self.param_env
775         };
776         let val = if let Some(promoted) = gid.promoted {
777             self.tcx.const_eval_promoted(param_env, gid.instance, promoted)?
778         } else {
779             self.tcx.const_eval_instance(param_env, gid.instance, Some(self.tcx.span))?
780         };
781
782         // Even though `ecx.const_eval` is called from `eval_const_to_op` we can never have a
783         // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not
784         // return `ConstValue::Unevaluated`, which is the only way that `eval_const_to_op` will call
785         // `ecx.const_eval`.
786         self.eval_const_to_op(val, None)
787     }
788
789     pub fn const_eval_raw(
790         &self,
791         gid: GlobalId<'tcx>,
792     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
793         // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
794         // and thus don't care about the parameter environment. While we could just use
795         // `self.param_env`, that would mean we invoke the query to evaluate the static
796         // with different parameter environments, thus causing the static to be evaluated
797         // multiple times.
798         let param_env = if self.tcx.is_static(gid.instance.def_id()) {
799             ty::ParamEnv::reveal_all()
800         } else {
801             self.param_env
802         };
803         // We use `const_eval_raw` here, and get an unvalidated result.  That is okay:
804         // Our result will later be validated anyway, and there seems no good reason
805         // to have to fail early here.  This is also more consistent with
806         // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
807         let val = self.tcx.const_eval_raw(param_env.and(gid))?;
808         self.raw_const_to_mplace(val)
809     }
810
811     pub fn dump_place(&self, place: Place<M::PointerTag>) {
812         // Debug output
813         if !log_enabled!(::log::Level::Trace) {
814             return;
815         }
816         match place {
817             Place::Local { frame, local } => {
818                 let mut allocs = Vec::new();
819                 let mut msg = format!("{:?}", local);
820                 if frame != self.cur_frame() {
821                     write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap();
822                 }
823                 write!(msg, ":").unwrap();
824
825                 match self.stack[frame].locals[local].value {
826                     LocalValue::Dead => write!(msg, " is dead").unwrap(),
827                     LocalValue::Uninitialized => write!(msg, " is uninitialized").unwrap(),
828                     LocalValue::Live(Operand::Indirect(mplace)) => match mplace.ptr {
829                         Scalar::Ptr(ptr) => {
830                             write!(
831                                 msg,
832                                 " by align({}){} ref:",
833                                 mplace.align.bytes(),
834                                 match mplace.meta {
835                                     MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta),
836                                     MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(),
837                                 }
838                             )
839                             .unwrap();
840                             allocs.push(ptr.alloc_id);
841                         }
842                         ptr => write!(msg, " by integral ref: {:?}", ptr).unwrap(),
843                     },
844                     LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
845                         write!(msg, " {:?}", val).unwrap();
846                         if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val {
847                             allocs.push(ptr.alloc_id);
848                         }
849                     }
850                     LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
851                         write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
852                         if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val1 {
853                             allocs.push(ptr.alloc_id);
854                         }
855                         if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val2 {
856                             allocs.push(ptr.alloc_id);
857                         }
858                     }
859                 }
860
861                 trace!("{}", msg);
862                 self.memory.dump_allocs(allocs);
863             }
864             Place::Ptr(mplace) => match mplace.ptr {
865                 Scalar::Ptr(ptr) => {
866                     trace!("by align({}) ref:", mplace.align.bytes());
867                     self.memory.dump_alloc(ptr.alloc_id);
868                 }
869                 ptr => trace!(" integral by ref: {:?}", ptr),
870             },
871         }
872     }
873
874     pub fn generate_stacktrace(&self, explicit_span: Option<Span>) -> Vec<FrameInfo<'tcx>> {
875         let mut last_span = None;
876         let mut frames = Vec::new();
877         for frame in self.stack().iter().rev() {
878             // make sure we don't emit frames that are duplicates of the previous
879             if explicit_span == Some(frame.span) {
880                 last_span = Some(frame.span);
881                 continue;
882             }
883             if let Some(last) = last_span {
884                 if last == frame.span {
885                     continue;
886                 }
887             } else {
888                 last_span = Some(frame.span);
889             }
890
891             let lint_root = frame.current_source_info().and_then(|source_info| {
892                 match &frame.body.source_scopes[source_info.scope].local_data {
893                     mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
894                     mir::ClearCrossCrate::Clear => None,
895                 }
896             });
897
898             frames.push(FrameInfo { call_site: frame.span, instance: frame.instance, lint_root });
899         }
900         trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span);
901         frames
902     }
903 }
904
905 impl<'ctx, 'mir, 'tcx, Tag, Extra> HashStable<StableHashingContext<'ctx>>
906     for Frame<'mir, 'tcx, Tag, Extra>
907 where
908     Extra: HashStable<StableHashingContext<'ctx>>,
909     Tag: HashStable<StableHashingContext<'ctx>>,
910 {
911     fn hash_stable(&self, hcx: &mut StableHashingContext<'ctx>, hasher: &mut StableHasher) {
912         self.body.hash_stable(hcx, hasher);
913         self.instance.hash_stable(hcx, hasher);
914         self.span.hash_stable(hcx, hasher);
915         self.return_to_block.hash_stable(hcx, hasher);
916         self.return_place.as_ref().map(|r| &**r).hash_stable(hcx, hasher);
917         self.locals.hash_stable(hcx, hasher);
918         self.block.hash_stable(hcx, hasher);
919         self.stmt.hash_stable(hcx, hasher);
920         self.extra.hash_stable(hcx, hasher);
921     }
922 }