]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir/src/interpret/eval_context.rs
CTFE/Miri engine Pointer type overhaul: make Scalar-to-Pointer conversion infallible
[rust.git] / compiler / rustc_mir / src / interpret / eval_context.rs
1 use std::cell::Cell;
2 use std::fmt;
3 use std::mem;
4
5 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
6 use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
7 use rustc_index::vec::IndexVec;
8 use rustc_macros::HashStable;
9 use rustc_middle::ich::StableHashingContext;
10 use rustc_middle::mir;
11 use rustc_middle::ty::layout::{self, TyAndLayout};
12 use rustc_middle::ty::{
13     self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
14 };
15 use rustc_session::Limit;
16 use rustc_span::{Pos, Span};
17 use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
18
19 use super::{
20     AllocId, GlobalId, Immediate, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory,
21     MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance, Scalar, ScalarMaybeUninit,
22     StackPopJump,
23 };
24 use crate::transform::validate::equal_up_to_regions;
25 use crate::util::storage::AlwaysLiveLocals;
26
27 pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
28     /// Stores the `Machine` instance.
29     ///
30     /// Note: the stack is provided by the machine.
31     pub machine: M,
32
33     /// The results of the type checker, from rustc.
34     /// The span in this is the "root" of the evaluation, i.e., the const
35     /// we are evaluating (if this is CTFE).
36     pub tcx: TyCtxtAt<'tcx>,
37
38     /// Bounds in scope for polymorphic evaluations.
39     pub(crate) param_env: ty::ParamEnv<'tcx>,
40
41     /// The virtual memory system.
42     pub memory: Memory<'mir, 'tcx, M>,
43
44     /// The recursion limit (cached from `tcx.recursion_limit(())`)
45     pub recursion_limit: Limit,
46 }
47
48 // The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
49 // boundary and dropped in the other thread, it would exit the span in the other thread.
50 struct SpanGuard(tracing::Span, std::marker::PhantomData<*const u8>);
51
52 impl SpanGuard {
53     /// By default a `SpanGuard` does nothing.
54     fn new() -> Self {
55         Self(tracing::Span::none(), std::marker::PhantomData)
56     }
57
58     /// If a span is entered, we exit the previous span (if any, normally none) and enter the
59     /// new span. This is mainly so we don't have to use `Option` for the `tracing_span` field of
60     /// `Frame` by creating a dummy span to being with and then entering it once the frame has
61     /// been pushed.
62     fn enter(&mut self, span: tracing::Span) {
63         // This executes the destructor on the previous instance of `SpanGuard`, ensuring that
64         // we never enter or exit more spans than vice versa. Unless you `mem::leak`, then we
65         // can't protect the tracing stack, but that'll just lead to weird logging, no actual
66         // problems.
67         *self = Self(span, std::marker::PhantomData);
68         self.0.with_subscriber(|(id, dispatch)| {
69             dispatch.enter(id);
70         });
71     }
72 }
73
74 impl Drop for SpanGuard {
75     fn drop(&mut self) {
76         self.0.with_subscriber(|(id, dispatch)| {
77             dispatch.exit(id);
78         });
79     }
80 }
81
82 /// A stack frame.
83 pub struct Frame<'mir, 'tcx, Tag = AllocId, Extra = ()> {
84     ////////////////////////////////////////////////////////////////////////////////
85     // Function and callsite information
86     ////////////////////////////////////////////////////////////////////////////////
87     /// The MIR for the function called on this frame.
88     pub body: &'mir mir::Body<'tcx>,
89
90     /// The def_id and substs of the current function.
91     pub instance: ty::Instance<'tcx>,
92
93     /// Extra data for the machine.
94     pub extra: Extra,
95
96     ////////////////////////////////////////////////////////////////////////////////
97     // Return place and locals
98     ////////////////////////////////////////////////////////////////////////////////
99     /// Work to perform when returning from this function.
100     pub return_to_block: StackPopCleanup,
101
102     /// The location where the result of the current stack frame should be written to,
103     /// and its layout in the caller.
104     pub return_place: Option<PlaceTy<'tcx, Tag>>,
105
106     /// The list of locals for this stack frame, stored in order as
107     /// `[return_ptr, arguments..., variables..., temporaries...]`.
108     /// The locals are stored as `Option<Value>`s.
109     /// `None` represents a local that is currently dead, while a live local
110     /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
111     pub locals: IndexVec<mir::Local, LocalState<'tcx, Tag>>,
112
113     /// The span of the `tracing` crate is stored here.
114     /// When the guard is dropped, the span is exited. This gives us
115     /// a full stack trace on all tracing statements.
116     tracing_span: SpanGuard,
117
118     ////////////////////////////////////////////////////////////////////////////////
119     // Current position within the function
120     ////////////////////////////////////////////////////////////////////////////////
121     /// If this is `Err`, we are not currently executing any particular statement in
122     /// this frame (can happen e.g. during frame initialization, and during unwinding on
123     /// frames without cleanup code).
124     /// We basically abuse `Result` as `Either`.
125     pub(super) loc: Result<mir::Location, Span>,
126 }
127
128 /// What we store about a frame in an interpreter backtrace.
129 #[derive(Debug)]
130 pub struct FrameInfo<'tcx> {
131     pub instance: ty::Instance<'tcx>,
132     pub span: Span,
133     pub lint_root: Option<hir::HirId>,
134 }
135
136 /// Unwind information.
137 #[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)]
138 pub enum StackPopUnwind {
139     /// The cleanup block.
140     Cleanup(mir::BasicBlock),
141     /// No cleanup needs to be done.
142     Skip,
143     /// Unwinding is not allowed (UB).
144     NotAllowed,
145 }
146
147 #[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
148 pub enum StackPopCleanup {
149     /// Jump to the next block in the caller, or cause UB if None (that's a function
150     /// that may never return). Also store layout of return place so
151     /// we can validate it at that layout.
152     /// `ret` stores the block we jump to on a normal return, while `unwind`
153     /// stores the block used for cleanup during unwinding.
154     Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind },
155     /// Just do nothing: Used by Main and for the `box_alloc` hook in miri.
156     /// `cleanup` says whether locals are deallocated. Static computation
157     /// wants them leaked to intern what they need (and just throw away
158     /// the entire `ecx` when it is done).
159     None { cleanup: bool },
160 }
161
162 /// State of a local variable including a memoized layout
163 #[derive(Clone, PartialEq, Eq, HashStable)]
164 pub struct LocalState<'tcx, Tag = AllocId> {
165     pub value: LocalValue<Tag>,
166     /// Don't modify if `Some`, this is only used to prevent computing the layout twice
167     #[stable_hasher(ignore)]
168     pub layout: Cell<Option<TyAndLayout<'tcx>>>,
169 }
170
171 /// Current value of a local variable
172 #[derive(Copy, Clone, PartialEq, Eq, HashStable)]
173 pub enum LocalValue<Tag = AllocId> {
174     /// This local is not currently alive, and cannot be used at all.
175     Dead,
176     /// This local is alive but not yet initialized. It can be written to
177     /// but not read from or its address taken. Locals get initialized on
178     /// first write because for unsized locals, we do not know their size
179     /// before that.
180     Uninitialized,
181     /// A normal, live local.
182     /// Mostly for convenience, we re-use the `Operand` type here.
183     /// This is an optimization over just always having a pointer here;
184     /// we can thus avoid doing an allocation when the local just stores
185     /// immediate values *and* never has its address taken.
186     Live(Operand<Tag>),
187 }
188
189 impl<Tag: Provenance> std::fmt::Debug for LocalValue<Tag> {
190     // Miri debug-prints these
191     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192         use LocalValue::*;
193         match self {
194             Dead => f.debug_tuple("Dead").finish(),
195             Uninitialized => f.debug_tuple("Uninitialized").finish(),
196             Live(o) => f.debug_tuple("Live").field(o).finish(),
197         }
198     }
199 }
200
201 impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> {
202     /// Read the local's value or error if the local is not yet live or not live anymore.
203     ///
204     /// Note: This may only be invoked from the `Machine::access_local` hook and not from
205     /// anywhere else. You may be invalidating machine invariants if you do!
206     pub fn access(&self) -> InterpResult<'tcx, Operand<Tag>> {
207         match self.value {
208             LocalValue::Dead => throw_ub!(DeadLocal),
209             LocalValue::Uninitialized => {
210                 bug!("The type checker should prevent reading from a never-written local")
211             }
212             LocalValue::Live(val) => Ok(val),
213         }
214     }
215
216     /// Overwrite the local.  If the local can be overwritten in place, return a reference
217     /// to do so; otherwise return the `MemPlace` to consult instead.
218     ///
219     /// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from
220     /// anywhere else. You may be invalidating machine invariants if you do!
221     pub fn access_mut(
222         &mut self,
223     ) -> InterpResult<'tcx, Result<&mut LocalValue<Tag>, MemPlace<Tag>>> {
224         match self.value {
225             LocalValue::Dead => throw_ub!(DeadLocal),
226             LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)),
227             ref mut
228             local @ (LocalValue::Live(Operand::Immediate(_)) | LocalValue::Uninitialized) => {
229                 Ok(Ok(local))
230             }
231         }
232     }
233 }
234
235 impl<'mir, 'tcx, Tag> Frame<'mir, 'tcx, Tag> {
236     pub fn with_extra<Extra>(self, extra: Extra) -> Frame<'mir, 'tcx, Tag, Extra> {
237         Frame {
238             body: self.body,
239             instance: self.instance,
240             return_to_block: self.return_to_block,
241             return_place: self.return_place,
242             locals: self.locals,
243             loc: self.loc,
244             extra,
245             tracing_span: self.tracing_span,
246         }
247     }
248 }
249
250 impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> {
251     /// Get the current location within the Frame.
252     ///
253     /// If this is `Err`, we are not currently executing any particular statement in
254     /// this frame (can happen e.g. during frame initialization, and during unwinding on
255     /// frames without cleanup code).
256     /// We basically abuse `Result` as `Either`.
257     ///
258     /// Used by priroda.
259     pub fn current_loc(&self) -> Result<mir::Location, Span> {
260         self.loc
261     }
262
263     /// Return the `SourceInfo` of the current instruction.
264     pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
265         self.loc.ok().map(|loc| self.body.source_info(loc))
266     }
267
268     pub fn current_span(&self) -> Span {
269         match self.loc {
270             Ok(loc) => self.body.source_info(loc).span,
271             Err(span) => span,
272         }
273     }
274 }
275
276 impl<'tcx> fmt::Display for FrameInfo<'tcx> {
277     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278         ty::tls::with(|tcx| {
279             if tcx.def_key(self.instance.def_id()).disambiguated_data.data
280                 == DefPathData::ClosureExpr
281             {
282                 write!(f, "inside closure")?;
283             } else {
284                 write!(f, "inside `{}`", self.instance)?;
285             }
286             if !self.span.is_dummy() {
287                 let lo = tcx.sess.source_map().lookup_char_pos(self.span.lo());
288                 write!(
289                     f,
290                     " at {}:{}:{}",
291                     lo.file.name.prefer_local(),
292                     lo.line,
293                     lo.col.to_usize() + 1
294                 )?;
295             }
296             Ok(())
297         })
298     }
299 }
300
301 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M> {
302     #[inline]
303     fn data_layout(&self) -> &TargetDataLayout {
304         &self.tcx.data_layout
305     }
306 }
307
308 impl<'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpCx<'mir, 'tcx, M>
309 where
310     M: Machine<'mir, 'tcx>,
311 {
312     #[inline]
313     fn tcx(&self) -> TyCtxt<'tcx> {
314         *self.tcx
315     }
316 }
317
318 impl<'mir, 'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'mir, 'tcx, M>
319 where
320     M: Machine<'mir, 'tcx>,
321 {
322     fn param_env(&self) -> ty::ParamEnv<'tcx> {
323         self.param_env
324     }
325 }
326
327 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> {
328     type Ty = Ty<'tcx>;
329     type TyAndLayout = InterpResult<'tcx, TyAndLayout<'tcx>>;
330
331     #[inline]
332     fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
333         self.tcx
334             .layout_of(self.param_env.and(ty))
335             .map_err(|layout| err_inval!(Layout(layout)).into())
336     }
337 }
338
339 /// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value.
340 /// This test should be symmetric, as it is primarily about layout compatibility.
341 pub(super) fn mir_assign_valid_types<'tcx>(
342     tcx: TyCtxt<'tcx>,
343     param_env: ParamEnv<'tcx>,
344     src: TyAndLayout<'tcx>,
345     dest: TyAndLayout<'tcx>,
346 ) -> bool {
347     // Type-changing assignments can happen when subtyping is used. While
348     // all normal lifetimes are erased, higher-ranked types with their
349     // late-bound lifetimes are still around and can lead to type
350     // differences. So we compare ignoring lifetimes.
351     if equal_up_to_regions(tcx, param_env, src.ty, dest.ty) {
352         // Make sure the layout is equal, too -- just to be safe. Miri really
353         // needs layout equality. For performance reason we skip this check when
354         // the types are equal. Equal types *can* have different layouts when
355         // enum downcast is involved (as enum variants carry the type of the
356         // enum), but those should never occur in assignments.
357         if cfg!(debug_assertions) || src.ty != dest.ty {
358             assert_eq!(src.layout, dest.layout);
359         }
360         true
361     } else {
362         false
363     }
364 }
365
366 /// Use the already known layout if given (but sanity check in debug mode),
367 /// or compute the layout.
368 #[cfg_attr(not(debug_assertions), inline(always))]
369 pub(super) fn from_known_layout<'tcx>(
370     tcx: TyCtxtAt<'tcx>,
371     param_env: ParamEnv<'tcx>,
372     known_layout: Option<TyAndLayout<'tcx>>,
373     compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>,
374 ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
375     match known_layout {
376         None => compute(),
377         Some(known_layout) => {
378             if cfg!(debug_assertions) {
379                 let check_layout = compute()?;
380                 if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) {
381                     span_bug!(
382                         tcx.span,
383                         "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}",
384                         known_layout.ty,
385                         check_layout.ty,
386                     );
387                 }
388             }
389             Ok(known_layout)
390         }
391     }
392 }
393
394 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
395     pub fn new(
396         tcx: TyCtxt<'tcx>,
397         root_span: Span,
398         param_env: ty::ParamEnv<'tcx>,
399         machine: M,
400         memory_extra: M::MemoryExtra,
401     ) -> Self {
402         InterpCx {
403             machine,
404             tcx: tcx.at(root_span),
405             param_env,
406             memory: Memory::new(tcx, memory_extra),
407             recursion_limit: tcx.recursion_limit(),
408         }
409     }
410
411     #[inline(always)]
412     pub fn cur_span(&self) -> Span {
413         self.stack()
414             .iter()
415             .rev()
416             .find(|frame| !frame.instance.def.requires_caller_location(*self.tcx))
417             .map_or(self.tcx.span, |f| f.current_span())
418     }
419
420     #[inline(always)]
421     pub fn scalar_to_ptr(&self, scalar: Scalar<M::PointerTag>) -> Pointer<Option<M::PointerTag>> {
422         self.memory.scalar_to_ptr(scalar)
423     }
424
425     /// Call this to turn untagged "global" pointers (obtained via `tcx`) into
426     /// the machine pointer to the allocation.  Must never be used
427     /// for any other pointers, nor for TLS statics.
428     ///
429     /// Using the resulting pointer represents a *direct* access to that memory
430     /// (e.g. by directly using a `static`),
431     /// as opposed to access through a pointer that was created by the program.
432     ///
433     /// This function can fail only if `ptr` points to an `extern static`.
434     #[inline(always)]
435     pub fn global_base_pointer(&self, ptr: Pointer) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
436         self.memory.global_base_pointer(ptr)
437     }
438
439     #[inline(always)]
440     pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] {
441         M::stack(self)
442     }
443
444     #[inline(always)]
445     pub(crate) fn stack_mut(
446         &mut self,
447     ) -> &mut Vec<Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>> {
448         M::stack_mut(self)
449     }
450
451     #[inline(always)]
452     pub fn frame_idx(&self) -> usize {
453         let stack = self.stack();
454         assert!(!stack.is_empty());
455         stack.len() - 1
456     }
457
458     #[inline(always)]
459     pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
460         self.stack().last().expect("no call frames exist")
461     }
462
463     #[inline(always)]
464     pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
465         self.stack_mut().last_mut().expect("no call frames exist")
466     }
467
468     #[inline(always)]
469     pub(super) fn body(&self) -> &'mir mir::Body<'tcx> {
470         self.frame().body
471     }
472
473     #[inline(always)]
474     pub fn sign_extend(&self, value: u128, ty: TyAndLayout<'_>) -> u128 {
475         assert!(ty.abi.is_signed());
476         ty.size.sign_extend(value)
477     }
478
479     #[inline(always)]
480     pub fn truncate(&self, value: u128, ty: TyAndLayout<'_>) -> u128 {
481         ty.size.truncate(value)
482     }
483
484     #[inline]
485     pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
486         ty.is_freeze(self.tcx, self.param_env)
487     }
488
489     pub fn load_mir(
490         &self,
491         instance: ty::InstanceDef<'tcx>,
492         promoted: Option<mir::Promoted>,
493     ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
494         // do not continue if typeck errors occurred (can only occur in local crate)
495         let def = instance.with_opt_param();
496         if let Some(def) = def.as_local() {
497             if self.tcx.has_typeck_results(def.did) {
498                 if let Some(error_reported) = self.tcx.typeck_opt_const_arg(def).tainted_by_errors {
499                     throw_inval!(AlreadyReported(error_reported))
500                 }
501             }
502         }
503         trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
504         if let Some(promoted) = promoted {
505             return Ok(&self.tcx.promoted_mir_opt_const_arg(def)[promoted]);
506         }
507         M::load_mir(self, instance)
508     }
509
510     /// Call this on things you got out of the MIR (so it is as generic as the current
511     /// stack frame), to bring it into the proper environment for this interpreter.
512     pub(super) fn subst_from_current_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
513         &self,
514         value: T,
515     ) -> T {
516         self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
517     }
518
519     /// Call this on things you got out of the MIR (so it is as generic as the provided
520     /// stack frame), to bring it into the proper environment for this interpreter.
521     pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
522         &self,
523         frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
524         value: T,
525     ) -> T {
526         frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value)
527     }
528
529     /// The `substs` are assumed to already be in our interpreter "universe" (param_env).
530     pub(super) fn resolve(
531         &self,
532         def: ty::WithOptConstParam<DefId>,
533         substs: SubstsRef<'tcx>,
534     ) -> InterpResult<'tcx, ty::Instance<'tcx>> {
535         trace!("resolve: {:?}, {:#?}", def, substs);
536         trace!("param_env: {:#?}", self.param_env);
537         trace!("substs: {:#?}", substs);
538         match ty::Instance::resolve_opt_const_arg(*self.tcx, self.param_env, def, substs) {
539             Ok(Some(instance)) => Ok(instance),
540             Ok(None) => throw_inval!(TooGeneric),
541
542             // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`.
543             Err(error_reported) => throw_inval!(AlreadyReported(error_reported)),
544         }
545     }
546
547     #[inline(always)]
548     pub fn layout_of_local(
549         &self,
550         frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
551         local: mir::Local,
552         layout: Option<TyAndLayout<'tcx>>,
553     ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
554         // `const_prop` runs into this with an invalid (empty) frame, so we
555         // have to support that case (mostly by skipping all caching).
556         match frame.locals.get(local).and_then(|state| state.layout.get()) {
557             None => {
558                 let layout = from_known_layout(self.tcx, self.param_env, layout, || {
559                     let local_ty = frame.body.local_decls[local].ty;
560                     let local_ty =
561                         self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty);
562                     self.layout_of(local_ty)
563                 })?;
564                 if let Some(state) = frame.locals.get(local) {
565                     // Layouts of locals are requested a lot, so we cache them.
566                     state.layout.set(Some(layout));
567                 }
568                 Ok(layout)
569             }
570             Some(layout) => Ok(layout),
571         }
572     }
573
574     /// Returns the actual dynamic size and alignment of the place at the given type.
575     /// Only the "meta" (metadata) part of the place matters.
576     /// This can fail to provide an answer for extern types.
577     pub(super) fn size_and_align_of(
578         &self,
579         metadata: &MemPlaceMeta<M::PointerTag>,
580         layout: &TyAndLayout<'tcx>,
581     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
582         if !layout.is_unsized() {
583             return Ok(Some((layout.size, layout.align.abi)));
584         }
585         match layout.ty.kind() {
586             ty::Adt(..) | ty::Tuple(..) => {
587                 // First get the size of all statically known fields.
588                 // Don't use type_of::sizing_type_of because that expects t to be sized,
589                 // and it also rounds up to alignment, which we want to avoid,
590                 // as the unsized field's alignment could be smaller.
591                 assert!(!layout.ty.is_simd());
592                 assert!(layout.fields.count() > 0);
593                 trace!("DST layout: {:?}", layout);
594
595                 let sized_size = layout.fields.offset(layout.fields.count() - 1);
596                 let sized_align = layout.align.abi;
597                 trace!(
598                     "DST {} statically sized prefix size: {:?} align: {:?}",
599                     layout.ty,
600                     sized_size,
601                     sized_align
602                 );
603
604                 // Recurse to get the size of the dynamically sized field (must be
605                 // the last field).  Can't have foreign types here, how would we
606                 // adjust alignment and size for them?
607                 let field = layout.field(self, layout.fields.count() - 1)?;
608                 let (unsized_size, unsized_align) =
609                     match self.size_and_align_of(metadata, &field)? {
610                         Some(size_and_align) => size_and_align,
611                         None => {
612                             // A field with extern type.  If this field is at offset 0, we behave
613                             // like the underlying extern type.
614                             // FIXME: Once we have made decisions for how to handle size and alignment
615                             // of `extern type`, this should be adapted.  It is just a temporary hack
616                             // to get some code to work that probably ought to work.
617                             if sized_size == Size::ZERO {
618                                 return Ok(None);
619                             } else {
620                                 span_bug!(
621                                     self.cur_span(),
622                                     "Fields cannot be extern types, unless they are at offset 0"
623                                 )
624                             }
625                         }
626                     };
627
628                 // FIXME (#26403, #27023): We should be adding padding
629                 // to `sized_size` (to accommodate the `unsized_align`
630                 // required of the unsized field that follows) before
631                 // summing it with `sized_size`. (Note that since #26403
632                 // is unfixed, we do not yet add the necessary padding
633                 // here. But this is where the add would go.)
634
635                 // Return the sum of sizes and max of aligns.
636                 let size = sized_size + unsized_size; // `Size` addition
637
638                 // Choose max of two known alignments (combined value must
639                 // be aligned according to more restrictive of the two).
640                 let align = sized_align.max(unsized_align);
641
642                 // Issue #27023: must add any necessary padding to `size`
643                 // (to make it a multiple of `align`) before returning it.
644                 let size = size.align_to(align);
645
646                 // Check if this brought us over the size limit.
647                 if size.bytes() >= self.tcx.data_layout.obj_size_bound() {
648                     throw_ub!(InvalidMeta("total size is bigger than largest supported object"));
649                 }
650                 Ok(Some((size, align)))
651             }
652             ty::Dynamic(..) => {
653                 let vtable = self.scalar_to_ptr(metadata.unwrap_meta());
654                 // Read size and align from vtable (already checks size).
655                 Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
656             }
657
658             ty::Slice(_) | ty::Str => {
659                 let len = metadata.unwrap_meta().to_machine_usize(self)?;
660                 let elem = layout.field(self, 0)?;
661
662                 // Make sure the slice is not too big.
663                 let size = elem.size.checked_mul(len, self).ok_or_else(|| {
664                     err_ub!(InvalidMeta("slice is bigger than largest supported object"))
665                 })?;
666                 Ok(Some((size, elem.align.abi)))
667             }
668
669             ty::Foreign(_) => Ok(None),
670
671             _ => span_bug!(self.cur_span(), "size_and_align_of::<{:?}> not supported", layout.ty),
672         }
673     }
674     #[inline]
675     pub fn size_and_align_of_mplace(
676         &self,
677         mplace: &MPlaceTy<'tcx, M::PointerTag>,
678     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
679         self.size_and_align_of(&mplace.meta, &mplace.layout)
680     }
681
682     pub fn push_stack_frame(
683         &mut self,
684         instance: ty::Instance<'tcx>,
685         body: &'mir mir::Body<'tcx>,
686         return_place: Option<&PlaceTy<'tcx, M::PointerTag>>,
687         return_to_block: StackPopCleanup,
688     ) -> InterpResult<'tcx> {
689         // first push a stack frame so we have access to the local substs
690         let pre_frame = Frame {
691             body,
692             loc: Err(body.span), // Span used for errors caused during preamble.
693             return_to_block,
694             return_place: return_place.copied(),
695             // empty local array, we fill it in below, after we are inside the stack frame and
696             // all methods actually know about the frame
697             locals: IndexVec::new(),
698             instance,
699             tracing_span: SpanGuard::new(),
700             extra: (),
701         };
702         let frame = M::init_frame_extra(self, pre_frame)?;
703         self.stack_mut().push(frame);
704
705         // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
706         for const_ in &body.required_consts {
707             let span = const_.span;
708             let const_ =
709                 self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal);
710             self.mir_const_to_op(&const_, None).map_err(|err| {
711                 // If there was an error, set the span of the current frame to this constant.
712                 // Avoiding doing this when evaluation succeeds.
713                 self.frame_mut().loc = Err(span);
714                 err
715             })?;
716         }
717
718         // Locals are initially uninitialized.
719         let dummy = LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) };
720         let mut locals = IndexVec::from_elem(dummy, &body.local_decls);
721
722         // Now mark those locals as dead that we do not want to initialize
723         // Mark locals that use `Storage*` annotations as dead on function entry.
724         let always_live = AlwaysLiveLocals::new(self.body());
725         for local in locals.indices() {
726             if !always_live.contains(local) {
727                 locals[local].value = LocalValue::Dead;
728             }
729         }
730         // done
731         self.frame_mut().locals = locals;
732         M::after_stack_push(self)?;
733         self.frame_mut().loc = Ok(mir::Location::START);
734
735         let span = info_span!("frame", "{}", instance);
736         self.frame_mut().tracing_span.enter(span);
737
738         Ok(())
739     }
740
741     /// Jump to the given block.
742     #[inline]
743     pub fn go_to_block(&mut self, target: mir::BasicBlock) {
744         self.frame_mut().loc = Ok(mir::Location { block: target, statement_index: 0 });
745     }
746
747     /// *Return* to the given `target` basic block.
748     /// Do *not* use for unwinding! Use `unwind_to_block` instead.
749     ///
750     /// If `target` is `None`, that indicates the function cannot return, so we raise UB.
751     pub fn return_to_block(&mut self, target: Option<mir::BasicBlock>) -> InterpResult<'tcx> {
752         if let Some(target) = target {
753             self.go_to_block(target);
754             Ok(())
755         } else {
756             throw_ub!(Unreachable)
757         }
758     }
759
760     /// *Unwind* to the given `target` basic block.
761     /// Do *not* use for returning! Use `return_to_block` instead.
762     ///
763     /// If `target` is `StackPopUnwind::Skip`, that indicates the function does not need cleanup
764     /// during unwinding, and we will just keep propagating that upwards.
765     ///
766     /// If `target` is `StackPopUnwind::NotAllowed`, that indicates the function does not allow
767     /// unwinding, and doing so is UB.
768     pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> {
769         self.frame_mut().loc = match target {
770             StackPopUnwind::Cleanup(block) => Ok(mir::Location { block, statement_index: 0 }),
771             StackPopUnwind::Skip => Err(self.frame_mut().body.span),
772             StackPopUnwind::NotAllowed => {
773                 throw_ub_format!("unwinding past a stack frame that does not allow unwinding")
774             }
775         };
776         Ok(())
777     }
778
779     /// Pops the current frame from the stack, deallocating the
780     /// memory for allocated locals.
781     ///
782     /// If `unwinding` is `false`, then we are performing a normal return
783     /// from a function. In this case, we jump back into the frame of the caller,
784     /// and continue execution as normal.
785     ///
786     /// If `unwinding` is `true`, then we are in the middle of a panic,
787     /// and need to unwind this frame. In this case, we jump to the
788     /// `cleanup` block for the function, which is responsible for running
789     /// `Drop` impls for any locals that have been initialized at this point.
790     /// The cleanup block ends with a special `Resume` terminator, which will
791     /// cause us to continue unwinding.
792     pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx> {
793         info!(
794             "popping stack frame ({})",
795             if unwinding { "during unwinding" } else { "returning from function" }
796         );
797
798         // Sanity check `unwinding`.
799         assert_eq!(
800             unwinding,
801             match self.frame().loc {
802                 Ok(loc) => self.body().basic_blocks()[loc.block].is_cleanup,
803                 Err(_) => true,
804             }
805         );
806
807         if unwinding && self.frame_idx() == 0 {
808             throw_ub_format!("unwinding past the topmost frame of the stack");
809         }
810
811         let frame =
812             self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
813
814         if !unwinding {
815             // Copy the return value to the caller's stack frame.
816             if let Some(ref return_place) = frame.return_place {
817                 let op = self.access_local(&frame, mir::RETURN_PLACE, None)?;
818                 self.copy_op_transmute(&op, return_place)?;
819                 trace!("{:?}", self.dump_place(**return_place));
820             } else {
821                 throw_ub!(Unreachable);
822             }
823         }
824
825         let return_to_block = frame.return_to_block;
826
827         // Now where do we jump next?
828
829         // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
830         // In that case, we return early. We also avoid validation in that case,
831         // because this is CTFE and the final value will be thoroughly validated anyway.
832         let cleanup = match return_to_block {
833             StackPopCleanup::Goto { .. } => true,
834             StackPopCleanup::None { cleanup, .. } => cleanup,
835         };
836
837         if !cleanup {
838             assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
839             assert!(!unwinding, "tried to skip cleanup during unwinding");
840             // Leak the locals, skip validation, skip machine hook.
841             return Ok(());
842         }
843
844         // Cleanup: deallocate all locals that are backed by an allocation.
845         for local in &frame.locals {
846             self.deallocate_local(local.value)?;
847         }
848
849         if M::after_stack_pop(self, frame, unwinding)? == StackPopJump::NoJump {
850             // The hook already did everything.
851             // We want to skip the `info!` below, hence early return.
852             return Ok(());
853         }
854         // Normal return, figure out where to jump.
855         if unwinding {
856             // Follow the unwind edge.
857             let unwind = match return_to_block {
858                 StackPopCleanup::Goto { unwind, .. } => unwind,
859                 StackPopCleanup::None { .. } => {
860                     panic!("Encountered StackPopCleanup::None when unwinding!")
861                 }
862             };
863             self.unwind_to_block(unwind)
864         } else {
865             // Follow the normal return edge.
866             match return_to_block {
867                 StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
868                 StackPopCleanup::None { .. } => Ok(()),
869             }
870         }
871     }
872
873     /// Mark a storage as live, killing the previous content.
874     pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> {
875         assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
876         trace!("{:?} is now live", local);
877
878         let local_val = LocalValue::Uninitialized;
879         // StorageLive expects the local to be dead, and marks it live.
880         let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
881         if !matches!(old, LocalValue::Dead) {
882             throw_ub_format!("StorageLive on a local that was already live");
883         }
884         Ok(())
885     }
886
887     pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> {
888         assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
889         trace!("{:?} is now dead", local);
890
891         // It is entirely okay for this local to be already dead (at least that's how we currently generate MIR)
892         let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead);
893         self.deallocate_local(old)?;
894         Ok(())
895     }
896
897     fn deallocate_local(&mut self, local: LocalValue<M::PointerTag>) -> InterpResult<'tcx> {
898         if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
899             // All locals have a backing allocation, even if the allocation is empty
900             // due to the local having ZST type.
901             trace!(
902                 "deallocating local {:?}: {:?}",
903                 local,
904                 self.memory.dump_alloc(ptr.provenance.unwrap().erase_for_fmt())
905             );
906             self.memory.deallocate(ptr, None, MemoryKind::Stack)?;
907         };
908         Ok(())
909     }
910
911     pub fn eval_to_allocation(
912         &self,
913         gid: GlobalId<'tcx>,
914     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
915         // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
916         // and thus don't care about the parameter environment. While we could just use
917         // `self.param_env`, that would mean we invoke the query to evaluate the static
918         // with different parameter environments, thus causing the static to be evaluated
919         // multiple times.
920         let param_env = if self.tcx.is_static(gid.instance.def_id()) {
921             ty::ParamEnv::reveal_all()
922         } else {
923             self.param_env
924         };
925         let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?;
926         self.raw_const_to_mplace(val)
927     }
928
929     #[must_use]
930     pub fn dump_place(&'a self, place: Place<M::PointerTag>) -> PlacePrinter<'a, 'mir, 'tcx, M> {
931         PlacePrinter { ecx: self, place }
932     }
933
934     #[must_use]
935     pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>> {
936         let mut frames = Vec::new();
937         for frame in self
938             .stack()
939             .iter()
940             .rev()
941             .skip_while(|frame| frame.instance.def.requires_caller_location(*self.tcx))
942         {
943             let lint_root = frame.current_source_info().and_then(|source_info| {
944                 match &frame.body.source_scopes[source_info.scope].local_data {
945                     mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
946                     mir::ClearCrossCrate::Clear => None,
947                 }
948             });
949             let span = frame.current_span();
950
951             frames.push(FrameInfo { span, instance: frame.instance, lint_root });
952         }
953         trace!("generate stacktrace: {:#?}", frames);
954         frames
955     }
956 }
957
958 #[doc(hidden)]
959 /// Helper struct for the `dump_place` function.
960 pub struct PlacePrinter<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
961     ecx: &'a InterpCx<'mir, 'tcx, M>,
962     place: Place<M::PointerTag>,
963 }
964
965 impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug
966     for PlacePrinter<'a, 'mir, 'tcx, M>
967 {
968     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
969         match self.place {
970             Place::Local { frame, local } => {
971                 let mut allocs = Vec::new();
972                 write!(fmt, "{:?}", local)?;
973                 if frame != self.ecx.frame_idx() {
974                     write!(fmt, " ({} frames up)", self.ecx.frame_idx() - frame)?;
975                 }
976                 write!(fmt, ":")?;
977
978                 match self.ecx.stack()[frame].locals[local].value {
979                     LocalValue::Dead => write!(fmt, " is dead")?,
980                     LocalValue::Uninitialized => write!(fmt, " is uninitialized")?,
981                     LocalValue::Live(Operand::Indirect(mplace)) => {
982                         write!(
983                             fmt,
984                             " by align({}){} ref {:?}:",
985                             mplace.align.bytes(),
986                             match mplace.meta {
987                                 MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta),
988                                 MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(),
989                             },
990                             mplace.ptr,
991                         )?;
992                         allocs.extend(mplace.ptr.map_erase_for_fmt().provenance);
993                     }
994                     LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
995                         write!(fmt, " {:?}", val)?;
996                         if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val {
997                             allocs.push(ptr.provenance.erase_for_fmt());
998                         }
999                     }
1000                     LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
1001                         write!(fmt, " ({:?}, {:?})", val1, val2)?;
1002                         if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val1 {
1003                             allocs.push(ptr.provenance.erase_for_fmt());
1004                         }
1005                         if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val2 {
1006                             allocs.push(ptr.provenance.erase_for_fmt());
1007                         }
1008                     }
1009                 }
1010
1011                 write!(fmt, ": {:?}", self.ecx.memory.dump_allocs(allocs))
1012             }
1013             Place::Ptr(mplace) => match mplace.ptr.map_erase_for_fmt().provenance {
1014                 Some(alloc_id) => write!(
1015                     fmt,
1016                     "by align({}) ref {:?}: {:?}",
1017                     mplace.align.bytes(),
1018                     mplace.ptr,
1019                     self.ecx.memory.dump_alloc(alloc_id)
1020                 ),
1021                 ptr => write!(fmt, " integral by ref: {:?}", ptr),
1022             },
1023         }
1024     }
1025 }
1026
1027 impl<'ctx, 'mir, 'tcx, Tag, Extra> HashStable<StableHashingContext<'ctx>>
1028     for Frame<'mir, 'tcx, Tag, Extra>
1029 where
1030     Extra: HashStable<StableHashingContext<'ctx>>,
1031     Tag: HashStable<StableHashingContext<'ctx>>,
1032 {
1033     fn hash_stable(&self, hcx: &mut StableHashingContext<'ctx>, hasher: &mut StableHasher) {
1034         // Exhaustive match on fields to make sure we forget no field.
1035         let Frame {
1036             body,
1037             instance,
1038             return_to_block,
1039             return_place,
1040             locals,
1041             loc,
1042             extra,
1043             tracing_span: _,
1044         } = self;
1045         body.hash_stable(hcx, hasher);
1046         instance.hash_stable(hcx, hasher);
1047         return_to_block.hash_stable(hcx, hasher);
1048         return_place.as_ref().map(|r| &**r).hash_stable(hcx, hasher);
1049         locals.hash_stable(hcx, hasher);
1050         loc.hash_stable(hcx, hasher);
1051         extra.hash_stable(hcx, hasher);
1052     }
1053 }