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};
56use either::{Either, Left, Right};
7use rustc_hiras hir;
8use rustc_hir::definitions::DefPathData;
9use rustc_index::IndexVec;
10use rustc_middle::mir;
11use rustc_middle::ty::layout::TyAndLayout;
12use rustc_middle::ty::{self, Ty, TyCtxt};
13use rustc_mir_dataflow::impls::always_storage_live_locals;
14use rustc_span::{Span, bug};
15use rustc_target::callconv::ArgAbi;
16use tracing::field::Empty;
17use tracing::{info_span, instrument, trace};
1819use super::{
20AllocId, CtfeProvenance, FnArg, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace,
21MemPlaceMeta, MemoryKind, Operand, PlaceTy, Pointer, Provenance, ReturnAction, Scalar,
22from_known_layout, interp_ok, throw_ub, throw_unsup,
23};
24use crate::{diagnostics, enter_trace_span};
2526// 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>);
2930impl SpanGuard {
31/// By default a `SpanGuard` does nothing.
32fn new() -> Self {
33Self(tracing::Span::none(), std::marker::PhantomData)
34 }
3536/// 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.
40fn 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);
46self.0.with_subscriber(|(id, dispatch)| {
47dispatch.enter(id);
48 });
49 }
50}
5152impl Dropfor SpanGuard {
53fn drop(&mut self) {
54self.0.with_subscriber(|(id, dispatch)| {
55dispatch.exit(id);
56 });
57 }
58}
5960/// 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.
66pub(super) body: &'tcx mir::Body<'tcx>,
6768/// The def_id and args of the current function.
69 /// Note that if this is the body of a promoted, the `instance` points
70 /// to the surrounding body!
71pub(super) instance: ty::Instance<'tcx>,
7273/// Extra data for the machine.
74pub extra: Extra,
7576////////////////////////////////////////////////////////////////////////////////
77 // Return place and locals
78 ////////////////////////////////////////////////////////////////////////////////
79/// Where to continue when returning from this function.
80return_cont: ReturnContinuation,
8182/// The location where the result of the current stack frame should be written to,
83 /// and its layout in the caller. This place is to be interpreted relative to the
84 /// *caller's* stack frame. We use a `PlaceTy` instead of an `MPlaceTy` since this
85 /// avoids having to move *all* return places into Miri's memory.
86return_place: PlaceTy<'tcx, Prov>,
8788/// The list of locals for this stack frame, stored in order as
89 /// `[return_ptr, arguments..., variables..., temporaries...]`.
90 /// The locals are stored as `Option<Value>`s.
91 /// `None` represents a local that is currently dead, while a live local
92 /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
93 ///
94 /// Do *not* access this directly; always go through the machine hook!
95pub(super) locals: IndexVec<mir::Local, LocalState<'tcx, Prov>>,
9697/// The complete variable argument list of this frame. Its elements must be dropped when the
98 /// frame is popped.
99pub(super) va_list: Vec<MPlaceTy<'tcx, Prov>>,
100101/// The implicit caller location argument that is passed by this function's caller, if any.
102 /// This is `Some` if and only if `instance.def.requires_caller_location` returns `true`.
103pub(super) track_caller_arg: Option<Span>,
104105/// The span of the `tracing` crate is stored here.
106 /// When the guard is dropped, the span is exited. This gives us
107 /// a full stack trace on all tracing statements.
108tracing_span: SpanGuard,
109110////////////////////////////////////////////////////////////////////////////////
111 // Current position within the function
112 ////////////////////////////////////////////////////////////////////////////////
113/// If this is `Right`, we are not currently executing any particular statement in
114 /// this frame (can happen e.g. during frame initialization, and during unwinding on
115 /// frames without cleanup code).
116 ///
117 /// Needs to be public because ConstProp does unspeakable things to it.
118pub(super) loc: Either<mir::Location, Span>,
119}
120121/// Where and how to continue when returning/unwinding from the current function.
122#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for ReturnContinuation {
}
#[automatically_derived]impl ::core::clone::Clone for ReturnContinuation {
#[inline]
fn clone(&self) -> Self {
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: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other) &&
match (self, other) {
(Self::Goto { ret: __self_0, unwind: __self_1 }, Self::Goto {
ret: __arg1_0, unwind: __arg1_1 }) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1,
(Self::Stop { cleanup: __self_0 }, Self::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 {
Self::Goto { ret: __self_0, unwind: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"Goto ret unwind", __self_0, &__self_1),
Self::Stop { cleanup: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"Stop cleanup", &__self_0),
}
}
}Debug)] // Miri debug-prints these
123pub enum ReturnContinuation {
124/// Jump to the next block in the caller, or cause UB if None (that's a function
125 /// that may never return).
126 /// `ret` stores the block we jump to on a normal return, while `unwind`
127 /// stores the block used for cleanup during unwinding.
128Goto { ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction },
129/// The root frame of the stack: nowhere else to jump to, so we stop.
130 /// `cleanup` says whether locals are deallocated. Static computation
131 /// wants them leaked to intern what they need (and just throw away
132 /// the entire `ecx` when it is done).
133Stop { cleanup: bool },
134}
135136/// State of a local variable including a memoized layout
137#[derive(#[automatically_derived]impl<'tcx, Prov: ::core::clone::Clone + Provenance>
::core::clone::Clone for LocalState<'tcx, Prov> {
#[inline]
fn clone(&self) -> Self {
LocalState {
value: ::core::clone::Clone::clone(&self.value),
layout: ::core::clone::Clone::clone(&self.layout),
}
}
}Clone)]
138pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
139 value: LocalValue<Prov>,
140/// Don't modify if `Some`, this is only used to prevent computing the layout twice.
141 /// Avoids computing the layout of locals that are never actually initialized.
142layout: Cell<Option<TyAndLayout<'tcx>>>,
143}
144145impl<Prov: Provenance> std::fmt::Debugfor LocalState<'_, Prov> {
146fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147f.debug_struct("LocalState")
148 .field("value", &self.value)
149 .field("ty", &self.layout.get().map(|l| l.ty))
150 .finish()
151 }
152}
153154/// Current value of a local variable
155///
156/// This does not store the type of the local; the type is given by `body.local_decls` and can never
157/// change, so by not storing here we avoid having to maintain that as an invariant.
158#[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) -> Self {
match self {
Self::Dead => LocalValue::Dead,
Self::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 {
Self::Dead => ::core::fmt::Formatter::write_str(f, "Dead"),
Self::Live(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "Live",
&__self_0),
}
}
}Debug)] // Miri debug-prints these
159pub(super) enum LocalValue<Prov: Provenance = CtfeProvenance> {
160/// This local is not currently alive, and cannot be used at all.
161Dead,
162/// A normal, live local.
163 /// Mostly for convenience, we re-use the `Operand` type here.
164 /// This is an optimization over just always having a pointer here;
165 /// we can thus avoid doing an allocation when the local just stores
166 /// immediate values *and* never has its address taken.
167Live(Operand<Prov>),
168}
169170impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
171pub fn make_live_uninit(&mut self) {
172self.value = LocalValue::Live(Operand::Immediate(Immediate::Uninit));
173 }
174175/// This is a hack because Miri needs a way to visit all the provenance in a `LocalState`
176 /// without having a layout or `TyCtxt` available, and we want to keep the `Operand` type
177 /// private. Does not count as a read of the local for the AM! It's a "ghost" read, like for
178 /// validation or similar purposes.
179pub fn as_mplace_or_imm_ghost(
180&self,
181 ) -> Option<Either<(Pointer<Option<Prov>>, MemPlaceMeta<Prov>), Immediate<Prov>>> {
182match self.value {
183 LocalValue::Dead => None,
184 LocalValue::Live(Operand::Indirect(mplace)) => Some(Left((mplace.ptr, mplace.meta))),
185 LocalValue::Live(Operand::Immediate(imm)) => Some(Right(imm)),
186 }
187 }
188189/// Read the local's value or error if the local is not yet live or not live anymore.
190#[inline(always)]
191pub(super) fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> {
192match &self.value {
193 LocalValue::Dead => do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::DeadLocal)throw_ub!(DeadLocal), // could even be "invalid program"?
194LocalValue::Live(val) => interp_ok(val),
195 }
196 }
197198/// Overwrite the local. If the local can be overwritten in place, return a reference
199 /// to do so; otherwise return the `MemPlace` to consult instead.
200#[inline(always)]
201pub(super) fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Prov>> {
202match &mut self.value {
203 LocalValue::Dead => do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::DeadLocal)throw_ub!(DeadLocal), // could even be "invalid program"?
204LocalValue::Live(val) => interp_ok(val),
205 }
206 }
207}
208209/// What we store about a frame in an interpreter backtrace.
210#[derive(#[automatically_derived]impl<'tcx> ::core::clone::Clone for FrameInfo<'tcx> {
#[inline]
fn clone(&self) -> Self {
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 span", &self.instance, &&self.span)
}
}Debug)]
211pub struct FrameInfo<'tcx> {
212pub instance: ty::Instance<'tcx>,
213pub span: Span,
214}
215216// FIXME: only used by miri, should be removed once translatable.
217impl<'tcx> fmt::Displayfor FrameInfo<'tcx> {
218fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219 ty::tls::with(|tcx| {
220if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
221f.write_fmt(format_args!("inside closure"))write!(f, "inside closure")222 } else {
223// Note: this triggers a `must_produce_diag` state, which means that if we ever
224 // get here we must emit a diagnostic. We should never display a `FrameInfo` unless
225 // we actually want to emit a warning or error to the user.
226f.write_fmt(format_args!("inside `{0}`", self.instance))write!(f, "inside `{}`", self.instance)227 }
228 })
229 }
230}
231232impl<'tcx> FrameInfo<'tcx> {
233pub(crate) fn as_note(&self, tcx: TyCtxt<'tcx>) -> diagnostics::FrameNote {
234let span = self.span;
235if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
236 diagnostics::FrameNote {
237 where_: "closure",
238span,
239 span_context: ::alloc::vec::Vec::new()vec![],
240 instance: String::new(),
241 times: 0,
242 has_label: false,
243 }
244 } else {
245let instance = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}", self.instance))
})format!("{}", self.instance);
246let span_context = crate::util::context_spans(tcx, span, self.instance.def_id());
247// Note: this triggers a `must_produce_diag` state, which means that if we ever get
248 // here we must emit a diagnostic. We should never display a `FrameInfo` unless we
249 // actually want to emit a warning or error to the user.
250diagnostics::FrameNote {
251 where_: "instance",
252span,
253span_context,
254instance,
255 times: 0,
256 has_label: false,
257 }
258 }
259 }
260}
261262impl<'tcx, Prov: Provenance> Frame<'tcx, Prov> {
263pub fn with_extra<Extra>(self, extra: Extra) -> Frame<'tcx, Prov, Extra> {
264Frame {
265 body: self.body,
266 instance: self.instance,
267extra,
268 return_cont: self.return_cont,
269 return_place: self.return_place,
270 locals: self.locals,
271 va_list: self.va_list,
272 track_caller_arg: self.track_caller_arg,
273 tracing_span: self.tracing_span,
274 loc: self.loc,
275 }
276 }
277}
278279impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> {
280/// Get the current location within the Frame.
281 ///
282 /// If this is `Right`, we are not currently executing any particular statement in
283 /// this frame (can happen e.g. during frame initialization, and during unwinding on
284 /// frames without cleanup code).
285 ///
286 /// Used by [priroda](https://github.com/oli-obk/priroda).
287pub fn current_loc(&self) -> Either<mir::Location, Span> {
288self.loc
289 }
290291pub fn body(&self) -> &'tcx mir::Body<'tcx> {
292self.body
293 }
294295pub fn instance(&self) -> ty::Instance<'tcx> {
296self.instance
297 }
298299pub fn return_place(&self) -> &PlaceTy<'tcx, Prov> {
300&self.return_place
301 }
302303pub fn return_cont(&self) -> ReturnContinuation {
304self.return_cont
305 }
306307pub fn locals(&self) -> &IndexVec<mir::Local, LocalState<'tcx, Prov>> {
308&self.locals
309 }
310311/// Return the `SourceInfo` of the current instruction.
312pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
313self.loc.left().map(|loc| self.body.source_info(loc))
314 }
315316pub fn current_span(&self) -> Span {
317match self.loc {
318Left(loc) => self.body.source_info(loc).span,
319Right(span) => span,
320 }
321 }
322323pub fn lint_root(&self, tcx: TyCtxt<'tcx>) -> Option<hir::HirId> {
324// We first try to get a HirId via the current source scope,
325 // and fall back to `body.source`.
326self.current_source_info()
327 .and_then(|source_info| match &self.body.source_scopes[source_info.scope].local_data {
328 mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
329 mir::ClearCrossCrate::Clear => None,
330 })
331 .or_else(|| {
332let def_id = self.body.source.def_id().as_local();
333def_id.map(|def_id| tcx.local_def_id_to_hir_id(def_id))
334 })
335 }
336337/// Returns the address of the buffer where the locals are stored. This is used by `Place` as a
338 /// sanity check to detect bugs where we mix up which stack frame a place refers to.
339#[inline(always)]
340pub(super) fn locals_addr(&self) -> usize {
341self.locals.raw.as_ptr().addr()
342 }
343344#[must_use]
345pub fn generate_stacktrace_from_stack(
346 stack: &[Self],
347 tcx: TyCtxt<'tcx>,
348 ) -> Vec<FrameInfo<'tcx>> {
349let mut frames = Vec::new();
350// This deliberately does *not* honor `requires_caller_location` since it is used for much
351 // more than just panics.
352for frame in stack.iter().rev() {
353let mut span = match frame.loc {
354 Left(loc) => {
355// If the stacktrace passes through MIR-inlined source scopes, add them.
356let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc);
357let mut scope_data = &frame.body.source_scopes[scope];
358while let Some((instance, call_span)) = scope_data.inlined {
359 frames.push(FrameInfo { span, instance });
360 span = call_span;
361 scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()];
362 }
363 span
364 }
365 Right(span) => span,
366 };
367if span.is_dummy() {
368// Some statements lack a proper span; point at the function instead.
369span = tcx.def_span(frame.instance.def_id());
370 }
371 frames.push(FrameInfo { span, instance: frame.instance });
372 }
373{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs:373",
"rustc_const_eval::interpret::stack",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/c980177d81d16f843a500905ac98c0cf3af1fd8d/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(&["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);
374frames375 }
376}
377378impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
379/// Very low-level helper that pushes a stack frame without initializing
380 /// the arguments or local variables.
381 ///
382 /// The high-level version of this is `init_stack_frame`.
383{}
#[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/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs"),
::tracing_core::__macro_support::Option::Some(383u32),
::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/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs:391",
"rustc_const_eval::interpret::stack",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs"),
::tracing_core::__macro_support::Option::Some(391u32),
::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(),
track_caller_arg: None,
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/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs"),
::tracing_core::__macro_support::Option::Some(422u32),
::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/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs"),
::tracing_core::__macro_support::Option::Some(437u32),
::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")]384pub(crate) fn push_stack_frame_raw(
385&mut self,
386 instance: ty::Instance<'tcx>,
387 body: &'tcx mir::Body<'tcx>,
388 return_place: &PlaceTy<'tcx, M::Provenance>,
389 return_cont: ReturnContinuation,
390 ) -> InterpResult<'tcx> {
391trace!("body: {:#?}", body);
392393// We can push a `Root` frame if and only if the stack is empty.
394debug_assert_eq!(
395self.stack().is_empty(),
396matches!(return_cont, ReturnContinuation::Stop { .. })
397 );
398399// First push a stack frame so we have access to `instantiate_from_current_frame` and other
400 // `self.frame()`-based functions.
401let dead_local = LocalState { value: LocalValue::Dead, layout: Cell::new(None) };
402let locals = IndexVec::from_elem(dead_local, &body.local_decls);
403let pre_frame = Frame {
404 body,
405 loc: Right(self.tcx.def_span(body.source.def_id())), // Span used for errors caused during preamble.
406return_cont,
407 return_place: return_place.clone(),
408 locals,
409 va_list: vec![],
410 track_caller_arg: None,
411 instance,
412 tracing_span: SpanGuard::new(),
413 extra: (),
414 };
415let frame = M::init_frame(self, pre_frame)?;
416self.stack_mut().push(frame);
417418// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
419for &const_ in body.required_consts() {
420// We can't use `eval_mir_constant` here as that assumes that all required consts have
421 // already been checked, so we need a separate tracing call.
422let _trace = enter_trace_span!(M, const_eval::required_consts, ?const_.const_);
423let c =
424self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
425 c.eval(*self.tcx, self.typing_env, const_.span).map_err(|err| {
426 err.emit_note(*self.tcx);
427 err
428 })?;
429 }
430431// Finish things up.
432M::after_stack_push(self)?;
433// `tracing_separate_thread` is used to instruct the tracing_chrome [tracing::Layer] in Miri
434 // to put the "frame" span on a separate trace thread/line than other spans, to make the
435 // visualization in <https://ui.perfetto.dev> easier to interpret. It is set to a value of
436 // [tracing::field::Empty] so that other tracing layers (e.g. the logger) will ignore it.
437let span = info_span!("frame", tracing_separate_thread = Empty, frame = %instance);
438self.frame_mut().tracing_span.enter(span);
439440 interp_ok(())
441 }
442443/// Low-level helper that pops a stack frame from the stack without any cleanup.
444 /// This invokes `before_stack_pop`.
445 /// After calling this function, you need to deal with the return value, and then
446 /// invoke `cleanup_stack_frame`.
447pub(super) fn pop_stack_frame_raw(
448&mut self,
449 ) -> InterpResult<'tcx, Frame<'tcx, M::Provenance, M::FrameExtra>> {
450 M::before_stack_pop(self)?;
451let frame =
452self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
453interp_ok(frame)
454 }
455456/// Deallocate local variables in the stack frame, and invoke `after_stack_pop`.
457pub(super) fn cleanup_stack_frame(
458&mut self,
459 unwinding: bool,
460 frame: Frame<'tcx, M::Provenance, M::FrameExtra>,
461 ) -> InterpResult<'tcx, ReturnAction> {
462let return_cont = frame.return_cont;
463464// Cleanup: deallocate locals.
465 // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
466 // We do this while the frame is still on the stack, so errors point to the callee.
467let cleanup = match return_cont {
468 ReturnContinuation::Goto { .. } => true,
469 ReturnContinuation::Stop { cleanup, .. } => cleanup,
470 };
471472if cleanup {
473for local in &frame.locals {
474self.deallocate_local(local.value)?;
475 }
476477// Deallocate any c-variadic arguments.
478self.deallocate_varargs(&frame.va_list)?;
479480// Call the machine hook, which determines the next steps.
481let return_action = M::after_stack_pop(self, frame, unwinding)?;
482{
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);
483interp_ok(return_action)
484 } else {
485// We also skip the machine hook when there's no cleanup. This not a real "pop" anyway.
486interp_ok(ReturnAction::NoCleanup)
487 }
488 }
489490/// Call this after `push_stack_frame_raw` and when all the other setup that needs to be done
491 /// is completed.
492pub(crate) fn push_stack_frame_done(&mut self) -> InterpResult<'tcx> {
493// Mark all locals as live that are not arguments and don't have `Storage*` annotations
494 // (this includes the return place, but not the arguments).
495self.storage_live(mir::RETURN_PLACE)?;
496497let body = self.body();
498let always_live = always_storage_live_locals(body);
499for local in body.vars_and_temps_iter() {
500if always_live.contains(local) {
501self.storage_live(local)?;
502 }
503 }
504505// Get ready to execute the first instruction in the stack frame.
506self.frame_mut().loc = Left(mir::Location::START);
507508interp_ok(())
509 }
510511pub fn storage_live_dyn(
512&mut self,
513 local: mir::Local,
514 meta: MemPlaceMeta<M::Provenance>,
515 ) -> InterpResult<'tcx> {
516{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs:516",
"rustc_const_eval::interpret::stack",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs"),
::tracing_core::__macro_support::Option::Some(516u32),
::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);
517518// We avoid `ty.is_trivially_sized` since that does something expensive for ADTs.
519fn is_very_trivially_sized(ty: Ty<'_>) -> bool {
520match ty.kind() {
521 ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
522 | ty::Uint(_)
523 | ty::Int(_)
524 | ty::Bool525 | ty::Float(_)
526 | ty::FnDef(..)
527 | ty::FnPtr(..)
528 | ty::RawPtr(..)
529 | ty::Char530 | ty::Ref(..)
531 | ty::Coroutine(..)
532 | ty::CoroutineWitness(..)
533 | ty::Array(..)
534 | ty::Closure(..)
535 | ty::CoroutineClosure(..)
536 | ty::Never537 | ty::Error(_) => true,
538539 ty::Str | ty::Slice(_) | ty::Dynamic(_, _) | ty::Foreign(..) => false,
540541 ty::Tuple(tys) => tys.last().is_none_or(|ty| is_very_trivially_sized(*ty)),
542543 ty::Pat(ty, ..) => is_very_trivially_sized(*ty),
544545// We don't want to do any queries, so there is not much we can do with ADTs.
546ty::Adt(..) => false,
547548 ty::UnsafeBinder(ty) => is_very_trivially_sized(ty.skip_binder()),
549550 ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false,
551552 ty::Infer(ty::TyVar(_)) => false,
553554 ty::Bound(..)
555 | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
556::rustc_span::macros::bug_impl(None,
format_args!("`is_very_trivially_sized` applied to unexpected type: {0}",
ty), Location::caller())bug!("`is_very_trivially_sized` applied to unexpected type: {}", ty)557 }
558 }
559 }
560561// This is a hot function, we avoid computing the layout when possible.
562 // `unsized_` will be `None` for sized types and `Some(layout)` for unsized types.
563let unsized_ = if is_very_trivially_sized(self.body().local_decls[local].ty) {
564None565 } else {
566// We need the layout.
567let layout = self.layout_of_local(self.frame(), local, None)?;
568if layout.is_sized() { None } else { Some(layout) }
569 };
570571let local_val = LocalValue::Live(if let Some(layout) = unsized_ {
572if !meta.has_meta() {
573do yeet ::rustc_middle::mir::interpret::InterpErrorKind::Unsupported(::rustc_middle::mir::interpret::UnsupportedOpInfo::UnsizedLocal);throw_unsup!(UnsizedLocal);
574 }
575// Need to allocate some memory, since `Immediate::Uninit` cannot be unsized.
576let dest_place = self.allocate_dyn(layout, MemoryKind::Stack, meta)?;
577 Operand::Indirect(*dest_place.mplace())
578 } else {
579// Just make this an efficient immediate.
580if !!meta.has_meta() {
::core::panicking::panic("assertion failed: !meta.has_meta()")
};assert!(!meta.has_meta()); // we're dropping the metadata
581 // Make sure the machine knows this "write" is happening. (This is important so that
582 // races involving local variable allocation can be detected by Miri.)
583M::after_local_write(self, local, /*storage_live*/ true)?;
584// Note that not calling `layout_of` here does have one real consequence:
585 // if the type is too big, we'll only notice this when the local is actually initialized,
586 // which is a bit too late -- we should ideally notice this already here, when the memory
587 // is conceptually allocated. But given how rare that error is and that this is a hot function,
588 // we accept this downside for now.
589Operand::Immediate(Immediate::Uninit)
590 });
591592// If the local is already live, deallocate its old memory.
593let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
594self.deallocate_local(old)?;
595interp_ok(())
596 }
597598/// Mark a storage as live, killing the previous content.
599#[inline(always)]
600pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> {
601self.storage_live_dyn(local, MemPlaceMeta::None)
602 }
603604pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> {
605if !(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");
606{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs:606",
"rustc_const_eval::interpret::stack",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs"),
::tracing_core::__macro_support::Option::Some(606u32),
::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);
607608// If the local is already dead, this is a NOP.
609let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead);
610self.deallocate_local(old)?;
611interp_ok(())
612 }
613614fn deallocate_local(&mut self, local: LocalValue<M::Provenance>) -> InterpResult<'tcx> {
615if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
616// All locals have a backing allocation, even if the allocation is empty
617 // due to the local having ZST type. Hence we can `unwrap`.
618{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs:618",
"rustc_const_eval::interpret::stack",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs"),
::tracing_core::__macro_support::Option::Some(618u32),
::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!(
619"deallocating local {:?}: {:?}",
620 local,
621// Locals always have a `alloc_id` (they are never the result of a int2ptr).
622self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap())
623 );
624self.deallocate_ptr(ptr, None, MemoryKind::Stack)?;
625 };
626interp_ok(())
627 }
628629/// This is public because it is used by [Aquascope](https://github.com/cognitive-engineering-lab/aquascope/)
630 /// to analyze all the locals in a stack frame.
631#[inline(always)]
632pub fn layout_of_local(
633&self,
634 frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
635 local: mir::Local,
636 layout: Option<TyAndLayout<'tcx>>,
637 ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
638let state = &frame.locals[local];
639if let Some(layout) = state.layout.get() {
640return interp_ok(layout);
641 }
642643let layout = from_known_layout(self.tcx, self.typing_env, layout, || {
644let local_ty = frame.body.local_decls[local].ty;
645let local_ty =
646self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
647self.layout_of(local_ty).into()
648 })?;
649650// Layouts of locals are requested a lot, so we cache them.
651state.layout.set(Some(layout));
652interp_ok(layout)
653 }
654}
655656impl<'a, 'tcx: 'a, M: Machine<'tcx>> InterpCx<'tcx, M> {
657/// Consume the arguments provided by the iterator and store them as a list
658 /// of variadic arguments. Return a list of the places that hold those arguments.
659pub(crate) fn allocate_varargs<I>(
660&mut self,
661 caller_args: I,
662 ) -> InterpResult<'tcx, Vec<MPlaceTy<'tcx, M::Provenance>>>
663where
664I: Iterator<Item = (&'a FnArg<'tcx, M::Provenance>, &'a ArgAbi<'tcx, Ty<'tcx>>)>,
665 {
666// Consume the remaining arguments and store them in fresh allocations.
667let mut varargs = Vec::new();
668for (fn_arg, _caller_abi) in caller_args {
669// FIXME: do we have to worry about in-place argument passing?
670let op = fn_arg.copy_fn_arg();
671let mplace = self.allocate(op.layout, MemoryKind::Stack)?;
672self.copy_op(&op, &mplace)?;
673674 varargs.push(mplace);
675 }
676677interp_ok(varargs)
678 }
679680/// Deallocate the variadic arguments in the list (that must have been created with `allocate_varargs`).
681fn deallocate_varargs(
682&mut self,
683 varargs: &[MPlaceTy<'tcx, M::Provenance>],
684 ) -> InterpResult<'tcx> {
685for vararg in varargs {
686let ptr = vararg.ptr();
687688{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs:688",
"rustc_const_eval::interpret::stack",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/c980177d81d16f843a500905ac98c0cf3af1fd8d/compiler/rustc_const_eval/src/interpret/stack.rs"),
::tracing_core::__macro_support::Option::Some(688u32),
::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!(
689"deallocating vararg {:?}: {:?}",
690 vararg,
691// Locals always have a `alloc_id` (they are never the result of a int2ptr).
692self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap())
693 );
694self.deallocate_ptr(ptr, None, MemoryKind::Stack)?;
695 }
696697interp_ok(())
698 }
699}
700701impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
702pub(super) fn print(
703&self,
704 allocs: &mut Vec<Option<AllocId>>,
705 fmt: &mut std::fmt::Formatter<'_>,
706 ) -> std::fmt::Result {
707match self.value {
708 LocalValue::Dead => fmt.write_fmt(format_args!(" is dead"))write!(fmt, " is dead")?,
709 LocalValue::Live(Operand::Immediate(Immediate::Uninit)) => {
710fmt.write_fmt(format_args!(" is uninitialized"))write!(fmt, " is uninitialized")?
711}
712 LocalValue::Live(Operand::Indirect(mplace)) => {
713fmt.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!(
714 fmt,
715" by {} ref {:?}:",
716match mplace.meta {
717 MemPlaceMeta::Meta(meta) => format!(" meta({meta:?})"),
718 MemPlaceMeta::None => String::new(),
719 },
720 mplace.ptr,
721 )?;
722allocs.extend(mplace.ptr.provenance.map(Provenance::get_alloc_id));
723 }
724 LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
725fmt.write_fmt(format_args!(" {0:?}", val))write!(fmt, " {val:?}")?;
726if let Scalar::Ptr(ptr, _size) = val {
727allocs.push(ptr.provenance.get_alloc_id());
728 }
729 }
730 LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
731fmt.write_fmt(format_args!(" ({0:?}, {1:?})", val1, val2))write!(fmt, " ({val1:?}, {val2:?})")?;
732if let Scalar::Ptr(ptr, _size) = val1 {
733allocs.push(ptr.provenance.get_alloc_id());
734 }
735if let Scalar::Ptr(ptr, _size) = val2 {
736allocs.push(ptr.provenance.get_alloc_id());
737 }
738 }
739 }
740741Ok(())
742 }
743}