Skip to main content

rustc_const_eval/interpret/
stack.rs

1//! Manages the low-level pushing and popping of stack frames and the (de)allocation of local variables.
2//! For handling of argument passing and return values, see the `call` module.
3use std::cell::Cell;
4use std::{fmt, mem};
5
6use either::{Either, Left, Right};
7use rustc_hir as hir;
8use rustc_hir::definitions::DefPathData;
9use rustc_index::IndexVec;
10use rustc_middle::ty::layout::TyAndLayout;
11use rustc_middle::ty::{self, Ty, TyCtxt};
12use rustc_middle::{bug, mir};
13use rustc_mir_dataflow::impls::always_storage_live_locals;
14use rustc_span::Span;
15use rustc_target::callconv::ArgAbi;
16use tracing::field::Empty;
17use tracing::{info_span, instrument, trace};
18
19use super::{
20    AllocId, CtfeProvenance, FnArg, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace,
21    MemPlaceMeta, MemoryKind, Operand, PlaceTy, Pointer, Provenance, ReturnAction, Scalar,
22    from_known_layout, interp_ok, throw_ub, throw_unsup,
23};
24use crate::{diagnostics, enter_trace_span};
25
26// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
27// boundary and dropped in the other thread, it would exit the span in the other thread.
28struct SpanGuard(tracing::Span, std::marker::PhantomData<*const u8>);
29
30impl SpanGuard {
31    /// By default a `SpanGuard` does nothing.
32    fn new() -> Self {
33        Self(tracing::Span::none(), std::marker::PhantomData)
34    }
35
36    /// If a span is entered, we exit the previous span (if any, normally none) and enter the
37    /// new span. This is mainly so we don't have to use `Option` for the `tracing_span` field of
38    /// `Frame` by creating a dummy span to being with and then entering it once the frame has
39    /// been pushed.
40    fn enter(&mut self, span: tracing::Span) {
41        // This executes the destructor on the previous instance of `SpanGuard`, ensuring that
42        // we never enter or exit more spans than vice versa. Unless you `mem::leak`, then we
43        // can't protect the tracing stack, but that'll just lead to weird logging, no actual
44        // problems.
45        *self = Self(span, std::marker::PhantomData);
46        self.0.with_subscriber(|(id, dispatch)| {
47            dispatch.enter(id);
48        });
49    }
50}
51
52impl Drop for SpanGuard {
53    fn drop(&mut self) {
54        self.0.with_subscriber(|(id, dispatch)| {
55            dispatch.exit(id);
56        });
57    }
58}
59
60/// A stack frame.
61pub struct Frame<'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> {
62    ////////////////////////////////////////////////////////////////////////////////
63    // Function and callsite information
64    ////////////////////////////////////////////////////////////////////////////////
65    /// The MIR for the function called on this frame.
66    pub(super) body: &'tcx mir::Body<'tcx>,
67
68    /// The def_id and args of the current function.
69    pub(super) instance: ty::Instance<'tcx>,
70
71    /// Extra data for the machine.
72    pub extra: Extra,
73
74    ////////////////////////////////////////////////////////////////////////////////
75    // Return place and locals
76    ////////////////////////////////////////////////////////////////////////////////
77    /// Where to continue when returning from this function.
78    return_cont: ReturnContinuation,
79
80    /// The location where the result of the current stack frame should be written to,
81    /// and its layout in the caller. This place is to be interpreted relative to the
82    /// *caller's* stack frame. We use a `PlaceTy` instead of an `MPlaceTy` since this
83    /// avoids having to move *all* return places into Miri's memory.
84    return_place: PlaceTy<'tcx, Prov>,
85
86    /// The list of locals for this stack frame, stored in order as
87    /// `[return_ptr, arguments..., variables..., temporaries...]`.
88    /// The locals are stored as `Option<Value>`s.
89    /// `None` represents a local that is currently dead, while a live local
90    /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
91    ///
92    /// Do *not* access this directly; always go through the machine hook!
93    pub(super) locals: IndexVec<mir::Local, LocalState<'tcx, Prov>>,
94
95    /// The complete variable argument list of this frame. Its elements must be dropped when the
96    /// frame is popped.
97    pub(super) va_list: Vec<MPlaceTy<'tcx, Prov>>,
98
99    /// The span of the `tracing` crate is stored here.
100    /// When the guard is dropped, the span is exited. This gives us
101    /// a full stack trace on all tracing statements.
102    tracing_span: SpanGuard,
103
104    ////////////////////////////////////////////////////////////////////////////////
105    // Current position within the function
106    ////////////////////////////////////////////////////////////////////////////////
107    /// If this is `Right`, we are not currently executing any particular statement in
108    /// this frame (can happen e.g. during frame initialization, and during unwinding on
109    /// frames without cleanup code).
110    ///
111    /// Needs to be public because ConstProp does unspeakable things to it.
112    pub(super) loc: Either<mir::Location, Span>,
113}
114
115/// Where and how to continue when returning/unwinding from the current function.
116#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ReturnContinuation { }
#[automatically_derived]
impl ::core::clone::Clone for ReturnContinuation {
    #[inline]
    fn clone(&self) -> ReturnContinuation {
        let _: ::core::clone::AssertParamIsClone<Option<mir::BasicBlock>>;
        let _: ::core::clone::AssertParamIsClone<mir::UnwindAction>;
        let _: ::core::clone::AssertParamIsClone<bool>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ReturnContinuation { }Copy, #[automatically_derived]
impl ::core::cmp::Eq for ReturnContinuation {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Option<mir::BasicBlock>>;
        let _: ::core::cmp::AssertParamIsEq<mir::UnwindAction>;
        let _: ::core::cmp::AssertParamIsEq<bool>;
    }
}Eq, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ReturnContinuation { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ReturnContinuation {
    #[inline]
    fn eq(&self, other: &ReturnContinuation) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (ReturnContinuation::Goto { ret: __self_0, unwind: __self_1 },
                    ReturnContinuation::Goto { ret: __arg1_0, unwind: __arg1_1
                    }) => __self_0 == __arg1_0 && __self_1 == __arg1_1,
                (ReturnContinuation::Stop { cleanup: __self_0 },
                    ReturnContinuation::Stop { cleanup: __arg1_0 }) =>
                    __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::fmt::Debug for ReturnContinuation {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            ReturnContinuation::Goto { ret: __self_0, unwind: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f, "Goto",
                    "ret", __self_0, "unwind", &__self_1),
            ReturnContinuation::Stop { cleanup: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f, "Stop",
                    "cleanup", &__self_0),
        }
    }
}Debug)] // Miri debug-prints these
117pub enum ReturnContinuation {
118    /// Jump to the next block in the caller, or cause UB if None (that's a function
119    /// that may never return).
120    /// `ret` stores the block we jump to on a normal return, while `unwind`
121    /// stores the block used for cleanup during unwinding.
122    Goto { ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction },
123    /// The root frame of the stack: nowhere else to jump to, so we stop.
124    /// `cleanup` says whether locals are deallocated. Static computation
125    /// wants them leaked to intern what they need (and just throw away
126    /// the entire `ecx` when it is done).
127    Stop { cleanup: bool },
128}
129
130/// State of a local variable including a memoized layout
131#[derive(#[automatically_derived]
impl<'tcx, Prov: ::core::clone::Clone + Provenance> ::core::clone::Clone for
    LocalState<'tcx, Prov> {
    #[inline]
    fn clone(&self) -> LocalState<'tcx, Prov> {
        LocalState {
            value: ::core::clone::Clone::clone(&self.value),
            layout: ::core::clone::Clone::clone(&self.layout),
        }
    }
}Clone)]
132pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
133    value: LocalValue<Prov>,
134    /// Don't modify if `Some`, this is only used to prevent computing the layout twice.
135    /// Avoids computing the layout of locals that are never actually initialized.
136    layout: Cell<Option<TyAndLayout<'tcx>>>,
137}
138
139impl<Prov: Provenance> std::fmt::Debug for LocalState<'_, Prov> {
140    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141        f.debug_struct("LocalState")
142            .field("value", &self.value)
143            .field("ty", &self.layout.get().map(|l| l.ty))
144            .finish()
145    }
146}
147
148/// Current value of a local variable
149///
150/// This does not store the type of the local; the type is given by `body.local_decls` and can never
151/// change, so by not storing here we avoid having to maintain that as an invariant.
152#[derive(#[automatically_derived]
impl<Prov: ::core::marker::Copy + Provenance> ::core::marker::Copy for
    LocalValue<Prov> {
}Copy, #[automatically_derived]
impl<Prov: ::core::clone::Clone + Provenance> ::core::clone::Clone for
    LocalValue<Prov> {
    #[inline]
    fn clone(&self) -> LocalValue<Prov> {
        match self {
            LocalValue::Dead => LocalValue::Dead,
            LocalValue::Live(__self_0) =>
                LocalValue::Live(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl<Prov: ::core::fmt::Debug + Provenance> ::core::fmt::Debug for
    LocalValue<Prov> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            LocalValue::Dead => ::core::fmt::Formatter::write_str(f, "Dead"),
            LocalValue::Live(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Live",
                    &__self_0),
        }
    }
}Debug)] // Miri debug-prints these
153pub(super) enum LocalValue<Prov: Provenance = CtfeProvenance> {
154    /// This local is not currently alive, and cannot be used at all.
155    Dead,
156    /// A normal, live local.
157    /// Mostly for convenience, we re-use the `Operand` type here.
158    /// This is an optimization over just always having a pointer here;
159    /// we can thus avoid doing an allocation when the local just stores
160    /// immediate values *and* never has its address taken.
161    Live(Operand<Prov>),
162}
163
164impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
165    pub fn make_live_uninit(&mut self) {
166        self.value = LocalValue::Live(Operand::Immediate(Immediate::Uninit));
167    }
168
169    /// This is a hack because Miri needs a way to visit all the provenance in a `LocalState`
170    /// without having a layout or `TyCtxt` available, and we want to keep the `Operand` type
171    /// private. Does not count as a read of the local for the AM! It's a "ghost" read, like for
172    /// validation or similar purposes.
173    pub fn as_mplace_or_imm_ghost(
174        &self,
175    ) -> Option<Either<(Pointer<Option<Prov>>, MemPlaceMeta<Prov>), Immediate<Prov>>> {
176        match self.value {
177            LocalValue::Dead => None,
178            LocalValue::Live(Operand::Indirect(mplace)) => Some(Left((mplace.ptr, mplace.meta))),
179            LocalValue::Live(Operand::Immediate(imm)) => Some(Right(imm)),
180        }
181    }
182
183    /// Read the local's value or error if the local is not yet live or not live anymore.
184    #[inline(always)]
185    pub(super) fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> {
186        match &self.value {
187            LocalValue::Dead => do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::DeadLocal)throw_ub!(DeadLocal), // could even be "invalid program"?
188            LocalValue::Live(val) => interp_ok(val),
189        }
190    }
191
192    /// Overwrite the local. If the local can be overwritten in place, return a reference
193    /// to do so; otherwise return the `MemPlace` to consult instead.
194    #[inline(always)]
195    pub(super) fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Prov>> {
196        match &mut self.value {
197            LocalValue::Dead => do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::DeadLocal)throw_ub!(DeadLocal), // could even be "invalid program"?
198            LocalValue::Live(val) => interp_ok(val),
199        }
200    }
201}
202
203/// What we store about a frame in an interpreter backtrace.
204#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for FrameInfo<'tcx> {
    #[inline]
    fn clone(&self) -> FrameInfo<'tcx> {
        FrameInfo {
            instance: ::core::clone::Clone::clone(&self.instance),
            span: ::core::clone::Clone::clone(&self.span),
        }
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for FrameInfo<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "FrameInfo",
            "instance", &self.instance, "span", &&self.span)
    }
}Debug)]
205pub struct FrameInfo<'tcx> {
206    pub instance: ty::Instance<'tcx>,
207    pub span: Span,
208}
209
210// FIXME: only used by miri, should be removed once translatable.
211impl<'tcx> fmt::Display for FrameInfo<'tcx> {
212    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213        ty::tls::with(|tcx| {
214            if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
215                f.write_fmt(format_args!("inside closure"))write!(f, "inside closure")
216            } else {
217                // Note: this triggers a `must_produce_diag` state, which means that if we ever
218                // get here we must emit a diagnostic. We should never display a `FrameInfo` unless
219                // we actually want to emit a warning or error to the user.
220                f.write_fmt(format_args!("inside `{0}`", self.instance))write!(f, "inside `{}`", self.instance)
221            }
222        })
223    }
224}
225
226impl<'tcx> FrameInfo<'tcx> {
227    pub(crate) fn as_note(&self, tcx: TyCtxt<'tcx>) -> diagnostics::FrameNote {
228        let span = self.span;
229        if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
230            diagnostics::FrameNote {
231                where_: "closure",
232                span,
233                instance: String::new(),
234                times: 0,
235                has_label: false,
236            }
237        } else {
238            let instance = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", self.instance))
    })format!("{}", self.instance);
239            // Note: this triggers a `must_produce_diag` state, which means that if we ever get
240            // here we must emit a diagnostic. We should never display a `FrameInfo` unless we
241            // actually want to emit a warning or error to the user.
242            diagnostics::FrameNote {
243                where_: "instance",
244                span,
245                instance,
246                times: 0,
247                has_label: false,
248            }
249        }
250    }
251}
252
253impl<'tcx, Prov: Provenance> Frame<'tcx, Prov> {
254    pub fn with_extra<Extra>(self, extra: Extra) -> Frame<'tcx, Prov, Extra> {
255        Frame {
256            body: self.body,
257            instance: self.instance,
258            return_cont: self.return_cont,
259            return_place: self.return_place,
260            locals: self.locals,
261            va_list: self.va_list,
262            loc: self.loc,
263            extra,
264            tracing_span: self.tracing_span,
265        }
266    }
267}
268
269impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> {
270    /// Get the current location within the Frame.
271    ///
272    /// If this is `Right`, we are not currently executing any particular statement in
273    /// this frame (can happen e.g. during frame initialization, and during unwinding on
274    /// frames without cleanup code).
275    ///
276    /// Used by [priroda](https://github.com/oli-obk/priroda).
277    pub fn current_loc(&self) -> Either<mir::Location, Span> {
278        self.loc
279    }
280
281    pub fn body(&self) -> &'tcx mir::Body<'tcx> {
282        self.body
283    }
284
285    pub fn instance(&self) -> ty::Instance<'tcx> {
286        self.instance
287    }
288
289    pub fn return_place(&self) -> &PlaceTy<'tcx, Prov> {
290        &self.return_place
291    }
292
293    pub fn return_cont(&self) -> ReturnContinuation {
294        self.return_cont
295    }
296
297    pub fn locals(&self) -> &IndexVec<mir::Local, LocalState<'tcx, Prov>> {
298        &self.locals
299    }
300
301    /// Return the `SourceInfo` of the current instruction.
302    pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
303        self.loc.left().map(|loc| self.body.source_info(loc))
304    }
305
306    pub fn current_span(&self) -> Span {
307        match self.loc {
308            Left(loc) => self.body.source_info(loc).span,
309            Right(span) => span,
310        }
311    }
312
313    pub fn lint_root(&self, tcx: TyCtxt<'tcx>) -> Option<hir::HirId> {
314        // We first try to get a HirId via the current source scope,
315        // and fall back to `body.source`.
316        self.current_source_info()
317            .and_then(|source_info| match &self.body.source_scopes[source_info.scope].local_data {
318                mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
319                mir::ClearCrossCrate::Clear => None,
320            })
321            .or_else(|| {
322                let def_id = self.body.source.def_id().as_local();
323                def_id.map(|def_id| tcx.local_def_id_to_hir_id(def_id))
324            })
325    }
326
327    /// Returns the address of the buffer where the locals are stored. This is used by `Place` as a
328    /// sanity check to detect bugs where we mix up which stack frame a place refers to.
329    #[inline(always)]
330    pub(super) fn locals_addr(&self) -> usize {
331        self.locals.raw.as_ptr().addr()
332    }
333
334    #[must_use]
335    pub fn generate_stacktrace_from_stack(
336        stack: &[Self],
337        tcx: TyCtxt<'tcx>,
338    ) -> Vec<FrameInfo<'tcx>> {
339        let mut frames = Vec::new();
340        // This deliberately does *not* honor `requires_caller_location` since it is used for much
341        // more than just panics.
342        for frame in stack.iter().rev() {
343            let mut span = match frame.loc {
344                Left(loc) => {
345                    // If the stacktrace passes through MIR-inlined source scopes, add them.
346                    let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc);
347                    let mut scope_data = &frame.body.source_scopes[scope];
348                    while let Some((instance, call_span)) = scope_data.inlined {
349                        frames.push(FrameInfo { span, instance });
350                        span = call_span;
351                        scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()];
352                    }
353                    span
354                }
355                Right(span) => span,
356            };
357            if span.is_dummy() {
358                // Some statements lack a proper span; point at the function instead.
359                span = tcx.def_span(frame.instance.def_id());
360            }
361            frames.push(FrameInfo { span, instance: frame.instance });
362        }
363        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs:363",
                        "rustc_const_eval::interpret::stack",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs"),
                        ::tracing_core::__macro_support::Option::Some(363u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::stack"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("generate stacktrace: {0:#?}",
                                                    frames) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};trace!("generate stacktrace: {:#?}", frames);
364        frames
365    }
366}
367
368impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
369    /// Very low-level helper that pushes a stack frame without initializing
370    /// the arguments or local variables.
371    ///
372    /// The high-level version of this is `init_stack_frame`.
373    {}
#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("push_stack_frame_raw",
                                    "rustc_const_eval::interpret::stack",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs"),
                                    ::tracing_core::__macro_support::Option::Some(373u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::stack"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("instance")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("instance");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&instance)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: InterpResult<'tcx> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("event /rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs:381",
                                    "rustc_const_eval::interpret::stack",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs"),
                                    ::tracing_core::__macro_support::Option::Some(381u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::stack"),
                                    ::tracing_core::field::FieldSet::new(&["message"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::EVENT)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let enabled =
                    ::tracing::Level::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        {
                            let interest = __CALLSITE.interest();
                            !interest.is_never() &&
                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                    interest)
                        };
                if enabled {
                    (|value_set: ::tracing::field::ValueSet|
                                {
                                    let meta = __CALLSITE.metadata();
                                    ::tracing::Event::dispatch(meta, &value_set);
                                    ;
                                })({
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("body: {0:#?}",
                                                                body) as &dyn ::tracing::field::Value))])
                        });
                } else { ; }
            };
            if true {
                {
                    match (&self.stack().is_empty(),
                            &#[allow(non_exhaustive_omitted_patterns)] match return_cont
                                    {
                                    ReturnContinuation::Stop { .. } => true,
                                    _ => false,
                                }) {
                        (left_val, right_val) => {
                            if !(*left_val == *right_val) {
                                let kind = ::core::panicking::AssertKind::Eq;
                                ::core::panicking::assert_failed(kind, &*left_val,
                                    &*right_val, ::core::option::Option::None);
                            }
                        }
                    }
                };
            };
            let dead_local =
                LocalState {
                    value: LocalValue::Dead,
                    layout: Cell::new(None),
                };
            let locals = IndexVec::from_elem(dead_local, &body.local_decls);
            let pre_frame =
                Frame {
                    body,
                    loc: Right(self.tcx.def_span(body.source.def_id())),
                    return_cont,
                    return_place: return_place.clone(),
                    locals,
                    va_list: ::alloc::vec::Vec::new(),
                    instance,
                    tracing_span: SpanGuard::new(),
                    extra: (),
                };
            let frame = M::init_frame(self, pre_frame)?;
            self.stack_mut().push(frame);
            for &const_ in body.required_consts() {
                let _trace =
                    <M as
                            crate::interpret::Machine>::enter_trace_span(||
                            {
                                use ::tracing::__macro_support::Callsite as _;
                                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                    {
                                        static META: ::tracing::Metadata<'static> =
                                            {
                                                ::tracing_core::metadata::Metadata::new("const_eval",
                                                    "rustc_const_eval::interpret::stack",
                                                    ::tracing::Level::INFO,
                                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs"),
                                                    ::tracing_core::__macro_support::Option::Some(411u32),
                                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::stack"),
                                                    ::tracing_core::field::FieldSet::new(&[{
                                                                        const NAME:
                                                                            ::tracing::__macro_support::FieldName<{
                                                                                ::tracing::__macro_support::FieldName::len("const_eval")
                                                                            }> =
                                                                            ::tracing::__macro_support::FieldName::new("const_eval");
                                                                        NAME.as_str()
                                                                    },
                                                                    {
                                                                        const NAME:
                                                                            ::tracing::__macro_support::FieldName<{
                                                                                ::tracing::__macro_support::FieldName::len("const_.const_")
                                                                            }> =
                                                                            ::tracing::__macro_support::FieldName::new("const_.const_");
                                                                        NAME.as_str()
                                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                    ::tracing::metadata::Kind::SPAN)
                                            };
                                        ::tracing::callsite::DefaultCallsite::new(&META)
                                    };
                                let mut interest = ::tracing::subscriber::Interest::never();
                                if ::tracing::Level::INFO <=
                                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                                ::tracing::Level::INFO <=
                                                    ::tracing::level_filters::LevelFilter::current() &&
                                            { interest = __CALLSITE.interest(); !interest.is_never() }
                                        &&
                                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                            interest) {
                                    let meta = __CALLSITE.metadata();
                                    ::tracing::Span::new(meta,
                                        &{
                                                #[allow(unused_imports)]
                                                use ::tracing::field::{debug, display, Value};
                                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::display(&"required_consts")
                                                                            as &dyn ::tracing::field::Value)),
                                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&const_.const_)
                                                                            as &dyn ::tracing::field::Value))])
                                            })
                                } else {
                                    let span =
                                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                                    {};
                                    span
                                }
                            });
                let c =
                    self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
                c.eval(*self.tcx, self.typing_env,
                            const_.span).map_err(|err|
                            { err.emit_note(*self.tcx); err })?;
            }
            M::after_stack_push(self)?;
            let span =
                {
                    use ::tracing::__macro_support::Callsite as _;
                    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                        {
                            static META: ::tracing::Metadata<'static> =
                                {
                                    ::tracing_core::metadata::Metadata::new("frame",
                                        "rustc_const_eval::interpret::stack",
                                        ::tracing::Level::INFO,
                                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs"),
                                        ::tracing_core::__macro_support::Option::Some(426u32),
                                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::stack"),
                                        ::tracing_core::field::FieldSet::new(&[{
                                                            const NAME:
                                                                ::tracing::__macro_support::FieldName<{
                                                                    ::tracing::__macro_support::FieldName::len("tracing_separate_thread")
                                                                }> =
                                                                ::tracing::__macro_support::FieldName::new("tracing_separate_thread");
                                                            NAME.as_str()
                                                        },
                                                        {
                                                            const NAME:
                                                                ::tracing::__macro_support::FieldName<{
                                                                    ::tracing::__macro_support::FieldName::len("frame")
                                                                }> =
                                                                ::tracing::__macro_support::FieldName::new("frame");
                                                            NAME.as_str()
                                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                        ::tracing::metadata::Kind::SPAN)
                                };
                            ::tracing::callsite::DefaultCallsite::new(&META)
                        };
                    let mut interest = ::tracing::subscriber::Interest::never();
                    if ::tracing::Level::INFO <=
                                        ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                    ::tracing::Level::INFO <=
                                        ::tracing::level_filters::LevelFilter::current() &&
                                { interest = __CALLSITE.interest(); !interest.is_never() }
                            &&
                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                interest) {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Span::new(meta,
                            &{
                                    #[allow(unused_imports)]
                                    use ::tracing::field::{debug, display, Value};
                                    meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&Empty
                                                                as &dyn ::tracing::field::Value)),
                                                    (::tracing::__macro_support::Option::Some(&::tracing::field::display(&instance)
                                                                as &dyn ::tracing::field::Value))])
                                })
                    } else {
                        let span =
                            ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                        {};
                        span
                    }
                };
            self.frame_mut().tracing_span.enter(span);
            interp_ok(())
        }
    }
}#[instrument(skip(self, body, return_place, return_cont), level = "debug")]
374    pub(crate) fn push_stack_frame_raw(
375        &mut self,
376        instance: ty::Instance<'tcx>,
377        body: &'tcx mir::Body<'tcx>,
378        return_place: &PlaceTy<'tcx, M::Provenance>,
379        return_cont: ReturnContinuation,
380    ) -> InterpResult<'tcx> {
381        trace!("body: {:#?}", body);
382
383        // We can push a `Root` frame if and only if the stack is empty.
384        debug_assert_eq!(
385            self.stack().is_empty(),
386            matches!(return_cont, ReturnContinuation::Stop { .. })
387        );
388
389        // First push a stack frame so we have access to `instantiate_from_current_frame` and other
390        // `self.frame()`-based functions.
391        let dead_local = LocalState { value: LocalValue::Dead, layout: Cell::new(None) };
392        let locals = IndexVec::from_elem(dead_local, &body.local_decls);
393        let pre_frame = Frame {
394            body,
395            loc: Right(self.tcx.def_span(body.source.def_id())), // Span used for errors caused during preamble.
396            return_cont,
397            return_place: return_place.clone(),
398            locals,
399            va_list: vec![],
400            instance,
401            tracing_span: SpanGuard::new(),
402            extra: (),
403        };
404        let frame = M::init_frame(self, pre_frame)?;
405        self.stack_mut().push(frame);
406
407        // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
408        for &const_ in body.required_consts() {
409            // We can't use `eval_mir_constant` here as that assumes that all required consts have
410            // already been checked, so we need a separate tracing call.
411            let _trace = enter_trace_span!(M, const_eval::required_consts, ?const_.const_);
412            let c =
413                self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
414            c.eval(*self.tcx, self.typing_env, const_.span).map_err(|err| {
415                err.emit_note(*self.tcx);
416                err
417            })?;
418        }
419
420        // Finish things up.
421        M::after_stack_push(self)?;
422        // `tracing_separate_thread` is used to instruct the tracing_chrome [tracing::Layer] in Miri
423        // to put the "frame" span on a separate trace thread/line than other spans, to make the
424        // visualization in <https://ui.perfetto.dev> easier to interpret. It is set to a value of
425        // [tracing::field::Empty] so that other tracing layers (e.g. the logger) will ignore it.
426        let span = info_span!("frame", tracing_separate_thread = Empty, frame = %instance);
427        self.frame_mut().tracing_span.enter(span);
428
429        interp_ok(())
430    }
431
432    /// Low-level helper that pops a stack frame from the stack without any cleanup.
433    /// This invokes `before_stack_pop`.
434    /// After calling this function, you need to deal with the return value, and then
435    /// invoke `cleanup_stack_frame`.
436    pub(super) fn pop_stack_frame_raw(
437        &mut self,
438    ) -> InterpResult<'tcx, Frame<'tcx, M::Provenance, M::FrameExtra>> {
439        M::before_stack_pop(self)?;
440        let frame =
441            self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
442        interp_ok(frame)
443    }
444
445    /// Deallocate local variables in the stack frame, and invoke `after_stack_pop`.
446    pub(super) fn cleanup_stack_frame(
447        &mut self,
448        unwinding: bool,
449        frame: Frame<'tcx, M::Provenance, M::FrameExtra>,
450    ) -> InterpResult<'tcx, ReturnAction> {
451        let return_cont = frame.return_cont;
452
453        // Cleanup: deallocate locals.
454        // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
455        // We do this while the frame is still on the stack, so errors point to the callee.
456        let cleanup = match return_cont {
457            ReturnContinuation::Goto { .. } => true,
458            ReturnContinuation::Stop { cleanup, .. } => cleanup,
459        };
460
461        if cleanup {
462            for local in &frame.locals {
463                self.deallocate_local(local.value)?;
464            }
465
466            // Deallocate any c-variadic arguments.
467            self.deallocate_varargs(&frame.va_list)?;
468
469            // Call the machine hook, which determines the next steps.
470            let return_action = M::after_stack_pop(self, frame, unwinding)?;
471            {
    match (&return_action, &ReturnAction::NoCleanup) {
        (left_val, right_val) => {
            if *left_val == *right_val {
                let kind = ::core::panicking::AssertKind::Ne;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_ne!(return_action, ReturnAction::NoCleanup);
472            interp_ok(return_action)
473        } else {
474            // We also skip the machine hook when there's no cleanup. This not a real "pop" anyway.
475            interp_ok(ReturnAction::NoCleanup)
476        }
477    }
478
479    /// Call this after `push_stack_frame_raw` and when all the other setup that needs to be done
480    /// is completed.
481    pub(crate) fn push_stack_frame_done(&mut self) -> InterpResult<'tcx> {
482        // Mark all locals as live that are not arguments and don't have `Storage*` annotations
483        // (this includes the return place, but not the arguments).
484        self.storage_live(mir::RETURN_PLACE)?;
485
486        let body = self.body();
487        let always_live = always_storage_live_locals(body);
488        for local in body.vars_and_temps_iter() {
489            if always_live.contains(local) {
490                self.storage_live(local)?;
491            }
492        }
493
494        // Get ready to execute the first instruction in the stack frame.
495        self.frame_mut().loc = Left(mir::Location::START);
496
497        interp_ok(())
498    }
499
500    pub fn storage_live_dyn(
501        &mut self,
502        local: mir::Local,
503        meta: MemPlaceMeta<M::Provenance>,
504    ) -> InterpResult<'tcx> {
505        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs:505",
                        "rustc_const_eval::interpret::stack",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs"),
                        ::tracing_core::__macro_support::Option::Some(505u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::stack"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("{0:?} is now live",
                                                    local) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};trace!("{:?} is now live", local);
506
507        // We avoid `ty.is_trivially_sized` since that does something expensive for ADTs.
508        fn is_very_trivially_sized(ty: Ty<'_>) -> bool {
509            match ty.kind() {
510                ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
511                | ty::Uint(_)
512                | ty::Int(_)
513                | ty::Bool
514                | ty::Float(_)
515                | ty::FnDef(..)
516                | ty::FnPtr(..)
517                | ty::RawPtr(..)
518                | ty::Char
519                | ty::Ref(..)
520                | ty::Coroutine(..)
521                | ty::CoroutineWitness(..)
522                | ty::Array(..)
523                | ty::Closure(..)
524                | ty::CoroutineClosure(..)
525                | ty::Never
526                | ty::Error(_) => true,
527
528                ty::Str | ty::Slice(_) | ty::Dynamic(_, _) | ty::Foreign(..) => false,
529
530                ty::Tuple(tys) => tys.last().is_none_or(|ty| is_very_trivially_sized(*ty)),
531
532                ty::Pat(ty, ..) => is_very_trivially_sized(*ty),
533
534                // We don't want to do any queries, so there is not much we can do with ADTs.
535                ty::Adt(..) => false,
536
537                ty::UnsafeBinder(ty) => is_very_trivially_sized(ty.skip_binder()),
538
539                ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false,
540
541                ty::Infer(ty::TyVar(_)) => false,
542
543                ty::Bound(..)
544                | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
545                    ::rustc_middle::util::bug::bug_fmt(format_args!("`is_very_trivially_sized` applied to unexpected type: {0}",
        ty))bug!("`is_very_trivially_sized` applied to unexpected type: {}", ty)
546                }
547            }
548        }
549
550        // This is a hot function, we avoid computing the layout when possible.
551        // `unsized_` will be `None` for sized types and `Some(layout)` for unsized types.
552        let unsized_ = if is_very_trivially_sized(self.body().local_decls[local].ty) {
553            None
554        } else {
555            // We need the layout.
556            let layout = self.layout_of_local(self.frame(), local, None)?;
557            if layout.is_sized() { None } else { Some(layout) }
558        };
559
560        let local_val = LocalValue::Live(if let Some(layout) = unsized_ {
561            if !meta.has_meta() {
562                do yeet ::rustc_middle::mir::interpret::InterpErrorKind::Unsupported(::rustc_middle::mir::interpret::UnsupportedOpInfo::UnsizedLocal);throw_unsup!(UnsizedLocal);
563            }
564            // Need to allocate some memory, since `Immediate::Uninit` cannot be unsized.
565            let dest_place = self.allocate_dyn(layout, MemoryKind::Stack, meta)?;
566            Operand::Indirect(*dest_place.mplace())
567        } else {
568            // Just make this an efficient immediate.
569            if !!meta.has_meta() {
    ::core::panicking::panic("assertion failed: !meta.has_meta()")
};assert!(!meta.has_meta()); // we're dropping the metadata
570            // Make sure the machine knows this "write" is happening. (This is important so that
571            // races involving local variable allocation can be detected by Miri.)
572            M::after_local_write(self, local, /*storage_live*/ true)?;
573            // Note that not calling `layout_of` here does have one real consequence:
574            // if the type is too big, we'll only notice this when the local is actually initialized,
575            // which is a bit too late -- we should ideally notice this already here, when the memory
576            // is conceptually allocated. But given how rare that error is and that this is a hot function,
577            // we accept this downside for now.
578            Operand::Immediate(Immediate::Uninit)
579        });
580
581        // If the local is already live, deallocate its old memory.
582        let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
583        self.deallocate_local(old)?;
584        interp_ok(())
585    }
586
587    /// Mark a storage as live, killing the previous content.
588    #[inline(always)]
589    pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> {
590        self.storage_live_dyn(local, MemPlaceMeta::None)
591    }
592
593    pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> {
594        if !(local != mir::RETURN_PLACE) {
    {
        ::core::panicking::panic_fmt(format_args!("Cannot make return place dead"));
    }
};assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
595        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs:595",
                        "rustc_const_eval::interpret::stack",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs"),
                        ::tracing_core::__macro_support::Option::Some(595u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::stack"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("{0:?} is now dead",
                                                    local) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};trace!("{:?} is now dead", local);
596
597        // If the local is already dead, this is a NOP.
598        let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead);
599        self.deallocate_local(old)?;
600        interp_ok(())
601    }
602
603    fn deallocate_local(&mut self, local: LocalValue<M::Provenance>) -> InterpResult<'tcx> {
604        if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
605            // All locals have a backing allocation, even if the allocation is empty
606            // due to the local having ZST type. Hence we can `unwrap`.
607            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs:607",
                        "rustc_const_eval::interpret::stack",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs"),
                        ::tracing_core::__macro_support::Option::Some(607u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::stack"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("deallocating local {0:?}: {1:?}",
                                                    local,
                                                    self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap()))
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};trace!(
608                "deallocating local {:?}: {:?}",
609                local,
610                // Locals always have a `alloc_id` (they are never the result of a int2ptr).
611                self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap())
612            );
613            self.deallocate_ptr(ptr, None, MemoryKind::Stack)?;
614        };
615        interp_ok(())
616    }
617
618    /// This is public because it is used by [Aquascope](https://github.com/cognitive-engineering-lab/aquascope/)
619    /// to analyze all the locals in a stack frame.
620    #[inline(always)]
621    pub fn layout_of_local(
622        &self,
623        frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
624        local: mir::Local,
625        layout: Option<TyAndLayout<'tcx>>,
626    ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
627        let state = &frame.locals[local];
628        if let Some(layout) = state.layout.get() {
629            return interp_ok(layout);
630        }
631
632        let layout = from_known_layout(self.tcx, self.typing_env, layout, || {
633            let local_ty = frame.body.local_decls[local].ty;
634            let local_ty =
635                self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
636            self.layout_of(local_ty).into()
637        })?;
638
639        // Layouts of locals are requested a lot, so we cache them.
640        state.layout.set(Some(layout));
641        interp_ok(layout)
642    }
643}
644
645impl<'a, 'tcx: 'a, M: Machine<'tcx>> InterpCx<'tcx, M> {
646    /// Consume the arguments provided by the iterator and store them as a list
647    /// of variadic arguments. Return a list of the places that hold those arguments.
648    pub(crate) fn allocate_varargs<I, J>(
649        &mut self,
650        caller_args: I,
651        mut callee_abis: J,
652    ) -> InterpResult<'tcx, Vec<MPlaceTy<'tcx, M::Provenance>>>
653    where
654        I: Iterator<Item = (&'a FnArg<'tcx, M::Provenance>, &'a ArgAbi<'tcx, Ty<'tcx>>)>,
655        J: Iterator<Item = (usize, &'a ArgAbi<'tcx, Ty<'tcx>>)>,
656    {
657        // Consume the remaining arguments and store them in fresh allocations.
658        let mut varargs = Vec::new();
659        for (fn_arg, caller_abi) in caller_args {
660            // The callee ABI is entirely computed based on which arguments the caller has
661            // provided so it should not be possible to get a mismatch here.
662            let (_idx, callee_abi) = callee_abis.next().unwrap();
663            if !self.check_argument_compat(caller_abi, callee_abi)? {
    ::core::panicking::panic("assertion failed: self.check_argument_compat(caller_abi, callee_abi)?")
};assert!(self.check_argument_compat(caller_abi, callee_abi)?);
664            // FIXME: do we have to worry about in-place argument passing?
665            let op = fn_arg.copy_fn_arg();
666            let mplace = self.allocate(op.layout, MemoryKind::Stack)?;
667            self.copy_op(&op, &mplace)?;
668
669            varargs.push(mplace);
670        }
671        if !callee_abis.next().is_none() {
    ::core::panicking::panic("assertion failed: callee_abis.next().is_none()")
};assert!(callee_abis.next().is_none());
672
673        interp_ok(varargs)
674    }
675
676    /// Deallocate the variadic arguments in the list (that must have been created with `allocate_varargs`).
677    fn deallocate_varargs(
678        &mut self,
679        varargs: &[MPlaceTy<'tcx, M::Provenance>],
680    ) -> InterpResult<'tcx> {
681        for vararg in varargs {
682            let ptr = vararg.ptr();
683
684            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs:684",
                        "rustc_const_eval::interpret::stack",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/stack.rs"),
                        ::tracing_core::__macro_support::Option::Some(684u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::stack"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("deallocating vararg {0:?}: {1:?}",
                                                    vararg,
                                                    self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap()))
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};trace!(
685                "deallocating vararg {:?}: {:?}",
686                vararg,
687                // Locals always have a `alloc_id` (they are never the result of a int2ptr).
688                self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap())
689            );
690            self.deallocate_ptr(ptr, None, MemoryKind::Stack)?;
691        }
692
693        interp_ok(())
694    }
695}
696
697impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
698    pub(super) fn print(
699        &self,
700        allocs: &mut Vec<Option<AllocId>>,
701        fmt: &mut std::fmt::Formatter<'_>,
702    ) -> std::fmt::Result {
703        match self.value {
704            LocalValue::Dead => fmt.write_fmt(format_args!(" is dead"))write!(fmt, " is dead")?,
705            LocalValue::Live(Operand::Immediate(Immediate::Uninit)) => {
706                fmt.write_fmt(format_args!(" is uninitialized"))write!(fmt, " is uninitialized")?
707            }
708            LocalValue::Live(Operand::Indirect(mplace)) => {
709                fmt.write_fmt(format_args!(" by {0} ref {1:?}:",
        match mplace.meta {
            MemPlaceMeta::Meta(meta) =>
                ::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!(" meta({0:?})", meta))
                    }),
            MemPlaceMeta::None => String::new(),
        }, mplace.ptr))write!(
710                    fmt,
711                    " by {} ref {:?}:",
712                    match mplace.meta {
713                        MemPlaceMeta::Meta(meta) => format!(" meta({meta:?})"),
714                        MemPlaceMeta::None => String::new(),
715                    },
716                    mplace.ptr,
717                )?;
718                allocs.extend(mplace.ptr.provenance.map(Provenance::get_alloc_id));
719            }
720            LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
721                fmt.write_fmt(format_args!(" {0:?}", val))write!(fmt, " {val:?}")?;
722                if let Scalar::Ptr(ptr, _size) = val {
723                    allocs.push(ptr.provenance.get_alloc_id());
724                }
725            }
726            LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
727                fmt.write_fmt(format_args!(" ({0:?}, {1:?})", val1, val2))write!(fmt, " ({val1:?}, {val2:?})")?;
728                if let Scalar::Ptr(ptr, _size) = val1 {
729                    allocs.push(ptr.provenance.get_alloc_id());
730                }
731                if let Scalar::Ptr(ptr, _size) = val2 {
732                    allocs.push(ptr.provenance.get_alloc_id());
733                }
734            }
735        }
736
737        Ok(())
738    }
739}