Skip to main content

rustc_const_eval/interpret/
operand.rs

1//! Functions concerning immediate values and operands, and reading from operands.
2//! All high-level functions to read from memory work on operands as sources.
3
4use std::assert_matches;
5
6use either::{Either, Left, Right};
7use rustc_abi as abi;
8use rustc_abi::{BackendRepr, HasDataLayout, Size};
9use rustc_hir::def::Namespace;
10use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, TyAndLayout};
11use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
12use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt};
13use rustc_middle::{bug, mir, span_bug, ty};
14use rustc_span::DUMMY_SP;
15use tracing::field::Empty;
16use tracing::trace;
17
18use super::{
19    CtfeProvenance, Frame, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta,
20    OffsetMode, PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub,
21    from_known_layout, interp_ok, mir_assign_valid_types, throw_ub,
22};
23use crate::enter_trace_span;
24
25/// An `Immediate` represents a single immediate self-contained Rust value.
26///
27/// For optimization of a few very common cases, there is also a representation for a pair of
28/// primitive values (`ScalarPair`). It allows Miri to avoid making allocations for checked binary
29/// operations and wide pointers. This idea was taken from rustc's codegen.
30/// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely
31/// defined on `Immediate`, and do not have to work with a `Place`.
32#[derive(#[automatically_derived]
impl<Prov: ::core::marker::Copy + Provenance> ::core::marker::Copy for
    Immediate<Prov> {
}Copy, #[automatically_derived]
impl<Prov: ::core::clone::Clone + Provenance> ::core::clone::Clone for
    Immediate<Prov> {
    #[inline]
    fn clone(&self) -> Immediate<Prov> {
        match self {
            Immediate::Scalar(__self_0) =>
                Immediate::Scalar(::core::clone::Clone::clone(__self_0)),
            Immediate::ScalarPair(__self_0, __self_1) =>
                Immediate::ScalarPair(::core::clone::Clone::clone(__self_0),
                    ::core::clone::Clone::clone(__self_1)),
            Immediate::Uninit => Immediate::Uninit,
        }
    }
}Clone, #[automatically_derived]
impl<Prov: ::core::fmt::Debug + Provenance> ::core::fmt::Debug for
    Immediate<Prov> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Immediate::Scalar(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Scalar",
                    &__self_0),
            Immediate::ScalarPair(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f,
                    "ScalarPair", __self_0, &__self_1),
            Immediate::Uninit =>
                ::core::fmt::Formatter::write_str(f, "Uninit"),
        }
    }
}Debug)]
33pub enum Immediate<Prov: Provenance = CtfeProvenance> {
34    /// A single scalar value (must have *initialized* `Scalar` ABI).
35    Scalar(Scalar<Prov>),
36    /// A pair of two scalar value (must have `ScalarPair` ABI where both fields are
37    /// `Scalar::Initialized`).
38    ScalarPair(Scalar<Prov>, Scalar<Prov>),
39    /// A value of fully uninitialized memory. Can have arbitrary size and layout, but must be sized.
40    Uninit,
41}
42
43impl<Prov: Provenance> From<Scalar<Prov>> for Immediate<Prov> {
44    #[inline(always)]
45    fn from(val: Scalar<Prov>) -> Self {
46        Immediate::Scalar(val)
47    }
48}
49
50impl<Prov: Provenance> Immediate<Prov> {
51    pub fn new_pointer_with_meta(
52        ptr: Pointer<Option<Prov>>,
53        meta: MemPlaceMeta<Prov>,
54        cx: &impl HasDataLayout,
55    ) -> Self {
56        let ptr = Scalar::from_maybe_pointer(ptr, cx);
57        match meta {
58            MemPlaceMeta::None => Immediate::from(ptr),
59            MemPlaceMeta::Meta(meta) => Immediate::ScalarPair(ptr, meta),
60        }
61    }
62
63    pub fn new_slice(ptr: Pointer<Option<Prov>>, len: u64, cx: &impl HasDataLayout) -> Self {
64        Immediate::ScalarPair(
65            Scalar::from_maybe_pointer(ptr, cx),
66            Scalar::from_target_usize(len, cx),
67        )
68    }
69
70    pub fn new_dyn_trait(
71        val: Pointer<Option<Prov>>,
72        vtable: Pointer<Option<Prov>>,
73        cx: &impl HasDataLayout,
74    ) -> Self {
75        Immediate::ScalarPair(
76            Scalar::from_maybe_pointer(val, cx),
77            Scalar::from_maybe_pointer(vtable, cx),
78        )
79    }
80
81    #[inline]
82    #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
83    pub fn to_scalar(self) -> Scalar<Prov> {
84        match self {
85            Immediate::Scalar(val) => val,
86            Immediate::ScalarPair { .. } => ::rustc_middle::util::bug::bug_fmt(format_args!("Got a scalar pair where a scalar was expected"))bug!("Got a scalar pair where a scalar was expected"),
87            Immediate::Uninit => ::rustc_middle::util::bug::bug_fmt(format_args!("Got uninit where a scalar was expected"))bug!("Got uninit where a scalar was expected"),
88        }
89    }
90
91    #[inline]
92    #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
93    pub fn to_scalar_int(self) -> ScalarInt {
94        self.to_scalar().try_to_scalar_int().unwrap()
95    }
96
97    #[inline]
98    #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
99    pub fn to_scalar_pair(self) -> (Scalar<Prov>, Scalar<Prov>) {
100        match self {
101            Immediate::ScalarPair(val1, val2) => (val1, val2),
102            Immediate::Scalar(..) => ::rustc_middle::util::bug::bug_fmt(format_args!("Got a scalar where a scalar pair was expected"))bug!("Got a scalar where a scalar pair was expected"),
103            Immediate::Uninit => ::rustc_middle::util::bug::bug_fmt(format_args!("Got uninit where a scalar pair was expected"))bug!("Got uninit where a scalar pair was expected"),
104        }
105    }
106
107    /// Returns the scalar from the first component and optionally the 2nd component as metadata.
108    #[inline]
109    #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
110    pub fn to_scalar_and_meta(self) -> (Scalar<Prov>, MemPlaceMeta<Prov>) {
111        match self {
112            Immediate::ScalarPair(val1, val2) => (val1, MemPlaceMeta::Meta(val2)),
113            Immediate::Scalar(val) => (val, MemPlaceMeta::None),
114            Immediate::Uninit => ::rustc_middle::util::bug::bug_fmt(format_args!("Got uninit where a scalar or scalar pair was expected"))bug!("Got uninit where a scalar or scalar pair was expected"),
115        }
116    }
117
118    /// Assert that this immediate is a valid value for the given ABI.
119    pub fn assert_matches_abi(self, abi: BackendRepr, msg: &str, cx: &impl HasDataLayout) {
120        match (self, abi) {
121            (Immediate::Scalar(scalar), BackendRepr::Scalar(s)) => {
122                {
    match (&scalar.size(), &s.size(cx)) {
        (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::Some(format_args!("{0}: scalar value has wrong size",
                            msg)));
            }
        }
    }
};assert_eq!(scalar.size(), s.size(cx), "{msg}: scalar value has wrong size");
123                if !#[allow(non_exhaustive_omitted_patterns)] match s.primitive() {
    abi::Primitive::Pointer(..) => true,
    _ => false,
}matches!(s.primitive(), abi::Primitive::Pointer(..)) {
124                    // This is not a pointer, it should not carry provenance.
125                    if !#[allow(non_exhaustive_omitted_patterns)] match scalar {
            Scalar::Int(..) => true,
            _ => false,
        } {
    {
        ::core::panicking::panic_fmt(format_args!("{0}: scalar value should be an integer, but has provenance",
                msg));
    }
};assert!(
126                        matches!(scalar, Scalar::Int(..)),
127                        "{msg}: scalar value should be an integer, but has provenance"
128                    );
129                }
130            }
131            (
132                Immediate::ScalarPair(a_val, b_val),
133                BackendRepr::ScalarPair { a, b, b_offset: _ },
134            ) => {
135                {
    match (&a_val.size(), &a.size(cx)) {
        (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::Some(format_args!("{0}: first component of scalar pair has wrong size",
                            msg)));
            }
        }
    }
};assert_eq!(
136                    a_val.size(),
137                    a.size(cx),
138                    "{msg}: first component of scalar pair has wrong size"
139                );
140                if !#[allow(non_exhaustive_omitted_patterns)] match a.primitive() {
    abi::Primitive::Pointer(..) => true,
    _ => false,
}matches!(a.primitive(), abi::Primitive::Pointer(..)) {
141                    if !#[allow(non_exhaustive_omitted_patterns)] match a_val {
            Scalar::Int(..) => true,
            _ => false,
        } {
    {
        ::core::panicking::panic_fmt(format_args!("{0}: first component of scalar pair should be an integer, but has provenance",
                msg));
    }
};assert!(
142                        matches!(a_val, Scalar::Int(..)),
143                        "{msg}: first component of scalar pair should be an integer, but has provenance"
144                    );
145                }
146                {
    match (&b_val.size(), &b.size(cx)) {
        (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::Some(format_args!("{0}: second component of scalar pair has wrong size",
                            msg)));
            }
        }
    }
};assert_eq!(
147                    b_val.size(),
148                    b.size(cx),
149                    "{msg}: second component of scalar pair has wrong size"
150                );
151                if !#[allow(non_exhaustive_omitted_patterns)] match b.primitive() {
    abi::Primitive::Pointer(..) => true,
    _ => false,
}matches!(b.primitive(), abi::Primitive::Pointer(..)) {
152                    if !#[allow(non_exhaustive_omitted_patterns)] match b_val {
            Scalar::Int(..) => true,
            _ => false,
        } {
    {
        ::core::panicking::panic_fmt(format_args!("{0}: second component of scalar pair should be an integer, but has provenance",
                msg));
    }
};assert!(
153                        matches!(b_val, Scalar::Int(..)),
154                        "{msg}: second component of scalar pair should be an integer, but has provenance"
155                    );
156                }
157            }
158            (Immediate::Uninit, _) => {
159                if !abi.is_sized() {
    {
        ::core::panicking::panic_fmt(format_args!("{0}: unsized immediates are not a thing",
                msg));
    }
};assert!(abi.is_sized(), "{msg}: unsized immediates are not a thing");
160            }
161            _ => {
162                ::rustc_middle::util::bug::bug_fmt(format_args!("{0}: value {1:?} does not match ABI {2:?})",
        msg, self, abi))bug!("{msg}: value {self:?} does not match ABI {abi:?})",)
163            }
164        }
165    }
166
167    pub fn clear_provenance<'tcx>(&mut self) -> InterpResult<'tcx> {
168        match self {
169            Immediate::Scalar(s) => {
170                s.clear_provenance()?;
171            }
172            Immediate::ScalarPair(a, b) => {
173                a.clear_provenance()?;
174                b.clear_provenance()?;
175            }
176            Immediate::Uninit => {}
177        }
178        interp_ok(())
179    }
180
181    pub fn has_provenance(&self) -> bool {
182        match self {
183            Immediate::Scalar(scalar) => #[allow(non_exhaustive_omitted_patterns)] match scalar {
    Scalar::Ptr { .. } => true,
    _ => false,
}matches!(scalar, Scalar::Ptr { .. }),
184            Immediate::ScalarPair(s1, s2) => {
185                #[allow(non_exhaustive_omitted_patterns)] match s1 {
    Scalar::Ptr { .. } => true,
    _ => false,
}matches!(s1, Scalar::Ptr { .. }) || #[allow(non_exhaustive_omitted_patterns)] match s2 {
    Scalar::Ptr { .. } => true,
    _ => false,
}matches!(s2, Scalar::Ptr { .. })
186            }
187            Immediate::Uninit => false,
188        }
189    }
190}
191
192// ScalarPair needs a type to interpret, so we often have an immediate and a type together
193// as input for binary and cast operations.
194#[derive(#[automatically_derived]
impl<'tcx, Prov: ::core::clone::Clone + Provenance> ::core::clone::Clone for
    ImmTy<'tcx, Prov> {
    #[inline]
    fn clone(&self) -> ImmTy<'tcx, Prov> {
        ImmTy {
            imm: ::core::clone::Clone::clone(&self.imm),
            layout: ::core::clone::Clone::clone(&self.layout),
        }
    }
}Clone)]
195pub struct ImmTy<'tcx, Prov: Provenance = CtfeProvenance> {
196    imm: Immediate<Prov>,
197    pub layout: TyAndLayout<'tcx>,
198}
199
200impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> {
201    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202        /// Helper function for printing a scalar to a FmtPrinter
203        fn print_scalar<'a, 'tcx, Prov: Provenance>(
204            p: &mut FmtPrinter<'a, 'tcx>,
205            s: Scalar<Prov>,
206            ty: Ty<'tcx>,
207        ) -> Result<(), std::fmt::Error> {
208            match s {
209                Scalar::Int(int) => p.pretty_print_const_scalar_int(int, ty, true),
210                Scalar::Ptr(ptr, _sz) => {
211                    // Just print the ptr value. `pretty_print_const_scalar_ptr` would also try to
212                    // print what is points to, which would fail since it has no access to the local
213                    // memory.
214                    p.pretty_print_const_pointer(ptr, ty)
215                }
216            }
217        }
218        ty::tls::with(|tcx| {
219            match self.imm {
220                Immediate::Scalar(s) => {
221                    let ty = tcx.lift(self.layout.ty);
222                    let s = FmtPrinter::print_string(tcx, Namespace::ValueNS, |p| {
223                        print_scalar(p, s, ty)
224                    })?;
225                    f.write_str(&s)
226                }
227                Immediate::ScalarPair(a, b) => {
228                    // FIXME(oli-obk): at least print tuples and slices nicely
229                    f.write_fmt(format_args!("({0:x}, {1:x}): {2}", a, b, self.layout.ty))write!(f, "({:x}, {:x}): {}", a, b, self.layout.ty)
230                }
231                Immediate::Uninit => {
232                    f.write_fmt(format_args!("uninit: {0}", self.layout.ty))write!(f, "uninit: {}", self.layout.ty)
233                }
234            }
235        })
236    }
237}
238
239impl<Prov: Provenance> std::fmt::Debug for ImmTy<'_, Prov> {
240    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241        // Printing `layout` results in too much noise; just print a nice version of the type.
242        f.debug_struct("ImmTy")
243            .field("imm", &self.imm)
244            .field("ty", &format_args!("{0}", self.layout.ty)format_args!("{}", self.layout.ty))
245            .finish()
246    }
247}
248
249impl<'tcx, Prov: Provenance> std::ops::Deref for ImmTy<'tcx, Prov> {
250    type Target = Immediate<Prov>;
251    #[inline(always)]
252    fn deref(&self) -> &Immediate<Prov> {
253        &self.imm
254    }
255}
256
257impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
258    #[inline]
259    pub fn from_scalar(val: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self {
260        if true {
    if !layout.backend_repr.is_scalar() {
        {
            ::core::panicking::panic_fmt(format_args!("`ImmTy::from_scalar` on non-scalar layout"));
        }
    };
};debug_assert!(layout.backend_repr.is_scalar(), "`ImmTy::from_scalar` on non-scalar layout");
261        if true {
    {
        match (&val.size(), &layout.size) {
            (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);
                }
            }
        }
    };
};debug_assert_eq!(val.size(), layout.size);
262        ImmTy { imm: val.into(), layout }
263    }
264
265    #[inline]
266    pub fn from_scalar_pair(a: Scalar<Prov>, b: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self {
267        if true {
    if !#[allow(non_exhaustive_omitted_patterns)] match layout.backend_repr {
                BackendRepr::ScalarPair { .. } => true,
                _ => false,
            } {
        {
            ::core::panicking::panic_fmt(format_args!("`ImmTy::from_scalar_pair` on non-scalar-pair layout"));
        }
    };
};debug_assert!(
268            matches!(layout.backend_repr, BackendRepr::ScalarPair { .. }),
269            "`ImmTy::from_scalar_pair` on non-scalar-pair layout"
270        );
271        let imm = Immediate::ScalarPair(a, b);
272        ImmTy { imm, layout }
273    }
274
275    #[inline(always)]
276    pub fn from_immediate(imm: Immediate<Prov>, layout: TyAndLayout<'tcx>) -> Self {
277        // Without a `cx` we cannot call `assert_matches_abi`.
278        if true {
    if !match (imm, layout.backend_repr) {
                (Immediate::Scalar(..), BackendRepr::Scalar(..)) => true,
                (Immediate::ScalarPair { .. }, BackendRepr::ScalarPair { .. })
                    => true,
                (Immediate::Uninit, _) if layout.is_sized() => true,
                _ => false,
            } {
        {
            ::core::panicking::panic_fmt(format_args!("immediate {0:?} does not fit to layout {1:?}",
                    imm, layout));
        }
    };
};debug_assert!(
279            match (imm, layout.backend_repr) {
280                (Immediate::Scalar(..), BackendRepr::Scalar(..)) => true,
281                (Immediate::ScalarPair { .. }, BackendRepr::ScalarPair { .. }) => true,
282                (Immediate::Uninit, _) if layout.is_sized() => true,
283                _ => false,
284            },
285            "immediate {imm:?} does not fit to layout {layout:?}",
286        );
287        ImmTy { imm, layout }
288    }
289
290    #[inline]
291    pub fn uninit(layout: TyAndLayout<'tcx>) -> Self {
292        if true {
    if !layout.is_sized() {
        {
            ::core::panicking::panic_fmt(format_args!("immediates must be sized"));
        }
    };
};debug_assert!(layout.is_sized(), "immediates must be sized");
293        ImmTy { imm: Immediate::Uninit, layout }
294    }
295
296    #[inline]
297    pub fn from_scalar_int(s: ScalarInt, layout: TyAndLayout<'tcx>) -> Self {
298        Self::from_scalar(Scalar::from(s), layout)
299    }
300
301    #[inline]
302    pub fn from_uint(i: impl Into<u128>, layout: TyAndLayout<'tcx>) -> Self {
303        Self::from_scalar(Scalar::from_uint(i, layout.size), layout)
304    }
305
306    #[inline]
307    pub fn from_int(i: impl Into<i128>, layout: TyAndLayout<'tcx>) -> Self {
308        Self::from_scalar(Scalar::from_int(i, layout.size), layout)
309    }
310
311    #[inline]
312    pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self {
313        // Can use any typing env, since `bool` is always monomorphic.
314        let layout = tcx
315            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tcx.types.bool))
316            .unwrap();
317        Self::from_scalar(Scalar::from_bool(b), layout)
318    }
319
320    #[inline]
321    pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self {
322        // Can use any typing env, since `Ordering` is always monomorphic.
323        let ty = tcx.ty_ordering_enum(DUMMY_SP);
324        let layout =
325            tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap();
326        Self::from_scalar(Scalar::Int(c.into()), layout)
327    }
328
329    pub fn from_pair(a: Self, b: Self, cx: &(impl HasTypingEnv<'tcx> + HasTyCtxt<'tcx>)) -> Self {
330        let layout = cx
331            .tcx()
332            .layout_of(
333                cx.typing_env().as_query_input(Ty::new_tup(cx.tcx(), &[a.layout.ty, b.layout.ty])),
334            )
335            .unwrap();
336        Self::from_scalar_pair(a.to_scalar(), b.to_scalar(), layout)
337    }
338
339    /// Return the immediate as a `ScalarInt`. Ensures that it has the size that the layout of the
340    /// immediate indicates.
341    #[inline]
342    pub fn to_scalar_int(&self) -> InterpResult<'tcx, ScalarInt> {
343        let s = self.to_scalar().to_scalar_int()?;
344        {
    match (&s.size(), &self.layout.size) {
        (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::Some(format_args!("scalar immediate size does not match layout")));
            }
        }
    }
};assert_eq!(s.size(), self.layout.size, "scalar immediate size does not match layout");
345        interp_ok(s)
346    }
347
348    #[inline]
349    pub fn to_const_int(self) -> ConstInt {
350        if !self.layout.ty.is_integral() {
    ::core::panicking::panic("assertion failed: self.layout.ty.is_integral()")
};assert!(self.layout.ty.is_integral());
351        let int = self.imm.to_scalar_int();
352        {
    match (&int.size(), &self.layout.size) {
        (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);
            }
        }
    }
};assert_eq!(int.size(), self.layout.size);
353        ConstInt::new(int, self.layout.ty.is_signed(), self.layout.ty.is_ptr_sized_integral())
354    }
355
356    #[inline]
357    #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
358    pub fn to_pair(self, cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>)) -> (Self, Self) {
359        let layout = self.layout;
360        let (val0, val1) = self.to_scalar_pair();
361        (
362            ImmTy::from_scalar(val0, layout.field(cx, 0)),
363            ImmTy::from_scalar(val1, layout.field(cx, 1)),
364        )
365    }
366
367    /// Compute the "sub-immediate" that is located within the `base` at the given offset with the
368    /// given layout.
369    // Not called `offset` to avoid confusion with the trait method.
370    fn offset_(&self, offset: Size, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self {
371        // Verify that the input matches its type.
372        if truecfg!(debug_assertions) {
373            self.assert_matches_abi(
374                self.layout.backend_repr,
375                "invalid input to Immediate::offset",
376                cx,
377            );
378        }
379        // `ImmTy` have already been checked to be in-bounds, so we can just check directly if this
380        // remains in-bounds. This cannot actually be violated since projections are type-checked
381        // and bounds-checked.
382        if !(offset + layout.size <= self.layout.size) {
    {
        ::core::panicking::panic_fmt(format_args!("attempting to project to field at offset {0} with size {1} into immediate with layout {2:#?}",
                offset.bytes(), layout.size.bytes(), self.layout));
    }
};assert!(
383            offset + layout.size <= self.layout.size,
384            "attempting to project to field at offset {} with size {} into immediate with layout {:#?}",
385            offset.bytes(),
386            layout.size.bytes(),
387            self.layout,
388        );
389        // This makes several assumptions about what layouts we will encounter; we match what
390        // codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`).
391        let inner_val: Immediate<_> = match (**self, self.layout.backend_repr) {
392            // If the entire value is uninit, then so is the field (can happen in ConstProp).
393            (Immediate::Uninit, _) => Immediate::Uninit,
394            // If the field is uninhabited, we can forget the data (can happen in ConstProp).
395            // `enum S { A(!), B, C }` is an example of an enum with Scalar layout that
396            // has an uninhabited variant, which means this case is possible.
397            _ if layout.is_uninhabited() => Immediate::Uninit,
398            // the field contains no information, can be left uninit
399            // (Scalar/ScalarPair can contain even aligned ZST, not just 1-ZST)
400            _ if layout.is_zst() => Immediate::Uninit,
401            // some fieldless enum variants can have non-zero size but still `Aggregate` ABI... try
402            // to detect those here and also give them no data
403            _ if #[allow(non_exhaustive_omitted_patterns)] match layout.backend_repr {
    BackendRepr::Memory { .. } => true,
    _ => false,
}matches!(layout.backend_repr, BackendRepr::Memory { .. })
404                && #[allow(non_exhaustive_omitted_patterns)] match layout.variants {
    abi::Variants::Single { .. } => true,
    _ => false,
}matches!(layout.variants, abi::Variants::Single { .. })
405                && #[allow(non_exhaustive_omitted_patterns)] match &layout.fields {
    abi::FieldsShape::Arbitrary { offsets, .. } if offsets.len() == 0 => true,
    _ => false,
}matches!(&layout.fields, abi::FieldsShape::Arbitrary { offsets, .. } if offsets.len() == 0) =>
406            {
407                Immediate::Uninit
408            }
409            // the field covers the entire type
410            _ if layout.size == self.layout.size => {
411                {
    match (&offset.bytes(), &0) {
        (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);
            }
        }
    }
};assert_eq!(offset.bytes(), 0);
412                **self
413            }
414            // extract fields from types with `ScalarPair` ABI
415            (
416                Immediate::ScalarPair(a_val, b_val),
417                BackendRepr::ScalarPair { a: _, b: _, b_offset },
418            ) => Immediate::from(if offset.bytes() == 0 {
419                a_val
420            } else {
421                {
    match (&offset, &b_offset) {
        (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);
            }
        }
    }
};assert_eq!(offset, b_offset);
422                b_val
423            }),
424            // everything else is a bug
425            _ => ::rustc_middle::util::bug::bug_fmt(format_args!("invalid field access on immediate {0} at offset {1}, original layout {2:#?}",
        self, offset.bytes(), self.layout))bug!(
426                "invalid field access on immediate {} at offset {}, original layout {:#?}",
427                self,
428                offset.bytes(),
429                self.layout
430            ),
431        };
432        // Ensure the new layout matches the new value.
433        inner_val.assert_matches_abi(
434            layout.backend_repr,
435            "invalid field type in Immediate::offset",
436            cx,
437        );
438
439        ImmTy::from_immediate(inner_val, layout)
440    }
441}
442
443impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> {
444    #[inline(always)]
445    fn layout(&self) -> TyAndLayout<'tcx> {
446        self.layout
447    }
448
449    #[inline(always)]
450    fn meta(&self) -> MemPlaceMeta<Prov> {
451        if true {
    if !self.layout.is_sized() {
        ::core::panicking::panic("assertion failed: self.layout.is_sized()")
    };
};debug_assert!(self.layout.is_sized()); // unsized ImmTy can only exist temporarily and should never reach this here
452        MemPlaceMeta::None
453    }
454
455    fn offset_with_meta<M: Machine<'tcx, Provenance = Prov>>(
456        &self,
457        offset: Size,
458        _mode: OffsetMode,
459        meta: MemPlaceMeta<Prov>,
460        layout: TyAndLayout<'tcx>,
461        ecx: &InterpCx<'tcx, M>,
462    ) -> InterpResult<'tcx, Self> {
463        {
    match meta {
        MemPlaceMeta::None => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "MemPlaceMeta::None", ::core::option::Option::None);
        }
    }
};assert_matches!(meta, MemPlaceMeta::None); // we can't store this anywhere anyway
464        interp_ok(self.offset_(offset, layout, ecx))
465    }
466
467    #[inline(always)]
468    fn to_op<M: Machine<'tcx, Provenance = Prov>>(
469        &self,
470        _ecx: &InterpCx<'tcx, M>,
471    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
472        interp_ok(self.clone().into())
473    }
474}
475
476/// An `Operand` is the result of computing a `mir::Operand`. It can be immediate,
477/// or still in memory. The latter is an optimization, to delay reading that chunk of
478/// memory and to avoid having to store arbitrary-sized data here.
479#[derive(#[automatically_derived]
impl<Prov: ::core::marker::Copy + Provenance> ::core::marker::Copy for
    Operand<Prov> {
}Copy, #[automatically_derived]
impl<Prov: ::core::clone::Clone + Provenance> ::core::clone::Clone for
    Operand<Prov> {
    #[inline]
    fn clone(&self) -> Operand<Prov> {
        match self {
            Operand::Immediate(__self_0) =>
                Operand::Immediate(::core::clone::Clone::clone(__self_0)),
            Operand::Indirect(__self_0) =>
                Operand::Indirect(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl<Prov: ::core::fmt::Debug + Provenance> ::core::fmt::Debug for
    Operand<Prov> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Operand::Immediate(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Immediate", &__self_0),
            Operand::Indirect(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Indirect", &__self_0),
        }
    }
}Debug)]
480pub(super) enum Operand<Prov: Provenance = CtfeProvenance> {
481    Immediate(Immediate<Prov>),
482    Indirect(MemPlace<Prov>),
483}
484
485#[derive(#[automatically_derived]
impl<'tcx, Prov: ::core::clone::Clone + Provenance> ::core::clone::Clone for
    OpTy<'tcx, Prov> {
    #[inline]
    fn clone(&self) -> OpTy<'tcx, Prov> {
        OpTy {
            op: ::core::clone::Clone::clone(&self.op),
            layout: ::core::clone::Clone::clone(&self.layout),
        }
    }
}Clone)]
486pub struct OpTy<'tcx, Prov: Provenance = CtfeProvenance> {
487    op: Operand<Prov>, // Keep this private; it helps enforce invariants.
488    pub layout: TyAndLayout<'tcx>,
489}
490
491impl<Prov: Provenance> std::fmt::Debug for OpTy<'_, Prov> {
492    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
493        // Printing `layout` results in too much noise; just print a nice version of the type.
494        f.debug_struct("OpTy")
495            .field("op", &self.op)
496            .field("ty", &format_args!("{0}", self.layout.ty)format_args!("{}", self.layout.ty))
497            .finish()
498    }
499}
500
501impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
502    #[inline(always)]
503    fn from(val: ImmTy<'tcx, Prov>) -> Self {
504        OpTy { op: Operand::Immediate(val.imm), layout: val.layout }
505    }
506}
507
508impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
509    #[inline(always)]
510    fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self {
511        OpTy { op: Operand::Indirect(*mplace.mplace()), layout: mplace.layout }
512    }
513}
514
515impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> {
516    #[inline(always)]
517    pub(super) fn op(&self) -> &Operand<Prov> {
518        &self.op
519    }
520
521    pub fn is_immediate_uninit(&self) -> bool {
522        #[allow(non_exhaustive_omitted_patterns)] match self.op {
    Operand::Immediate(Immediate::Uninit) => true,
    _ => false,
}matches!(self.op, Operand::Immediate(Immediate::Uninit))
523    }
524}
525
526impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> {
527    #[inline(always)]
528    fn layout(&self) -> TyAndLayout<'tcx> {
529        self.layout
530    }
531
532    #[inline]
533    fn meta(&self) -> MemPlaceMeta<Prov> {
534        match self.as_mplace_or_imm() {
535            Left(mplace) => mplace.meta(),
536            Right(_) => {
537                if true {
    if !self.layout.is_sized() {
        {
            ::core::panicking::panic_fmt(format_args!("unsized immediates are not a thing"));
        }
    };
};debug_assert!(self.layout.is_sized(), "unsized immediates are not a thing");
538                MemPlaceMeta::None
539            }
540        }
541    }
542
543    fn offset_with_meta<M: Machine<'tcx, Provenance = Prov>>(
544        &self,
545        offset: Size,
546        mode: OffsetMode,
547        meta: MemPlaceMeta<Prov>,
548        layout: TyAndLayout<'tcx>,
549        ecx: &InterpCx<'tcx, M>,
550    ) -> InterpResult<'tcx, Self> {
551        match self.as_mplace_or_imm() {
552            Left(mplace) => {
553                interp_ok(mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into())
554            }
555            Right(imm) => {
556                {
    match meta {
        MemPlaceMeta::None => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "MemPlaceMeta::None", ::core::option::Option::None);
        }
    }
};assert_matches!(meta, MemPlaceMeta::None); // no place to store metadata here
557                // Every part of an uninit is uninit.
558                interp_ok(imm.offset_(offset, layout, ecx).into())
559            }
560        }
561    }
562
563    #[inline(always)]
564    fn to_op<M: Machine<'tcx, Provenance = Prov>>(
565        &self,
566        _ecx: &InterpCx<'tcx, M>,
567    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
568        interp_ok(self.clone())
569    }
570}
571
572impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
573    /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`.
574    /// Returns `None` if the layout does not permit loading this as a value.
575    ///
576    /// This is an internal function; call `read_immediate` instead.
577    fn read_immediate_from_mplace_raw(
578        &self,
579        mplace: &MPlaceTy<'tcx, M::Provenance>,
580    ) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::Provenance>>> {
581        if mplace.layout.is_unsized() {
582            // Don't touch unsized
583            return interp_ok(None);
584        }
585
586        let Some(alloc) = self.get_place_alloc(mplace)? else {
587            // zero-sized type can be left uninit
588            return interp_ok(Some(ImmTy::uninit(mplace.layout)));
589        };
590
591        // It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point.
592        // However, `MaybeUninit<u64>` is considered a `Scalar` as far as its layout is concerned --
593        // and yet cannot be represented by an interpreter `Scalar`, since we have to handle the
594        // case where some of the bytes are initialized and others are not. So, we need an extra
595        // check that walks over the type of `mplace` to make sure it is truly correct to treat this
596        // like a `Scalar` (or `ScalarPair`).
597        interp_ok(match mplace.layout.backend_repr {
598            BackendRepr::Scalar(abi::Scalar::Initialized { value: s, .. }) => {
599                let size = s.size(self);
600                {
    match (&size, &mplace.layout.size) {
        (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::Some(format_args!("abi::Scalar size does not match layout size")));
            }
        }
    }
};assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size");
601                let scalar = alloc.read_scalar(
602                    alloc_range(Size::ZERO, size),
603                    /*read_provenance*/ #[allow(non_exhaustive_omitted_patterns)] match s {
    abi::Primitive::Pointer(_) => true,
    _ => false,
}matches!(s, abi::Primitive::Pointer(_)),
604                )?;
605                Some(ImmTy::from_scalar(scalar, mplace.layout))
606            }
607            BackendRepr::ScalarPair {
608                a: abi::Scalar::Initialized { value: a, .. },
609                b: abi::Scalar::Initialized { value: b, .. },
610                b_offset,
611            } => {
612                // We checked `ptr_align` above, so all fields will have the alignment they need.
613                // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
614                // which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
615                let (a_size, b_size) = (a.size(self), b.size(self));
616                if !(b_offset.bytes() > 0) {
    ::core::panicking::panic("assertion failed: b_offset.bytes() > 0")
};assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields
617                let a_val = alloc.read_scalar(
618                    alloc_range(Size::ZERO, a_size),
619                    /*read_provenance*/ #[allow(non_exhaustive_omitted_patterns)] match a {
    abi::Primitive::Pointer(_) => true,
    _ => false,
}matches!(a, abi::Primitive::Pointer(_)),
620                )?;
621                let b_val = alloc.read_scalar(
622                    alloc_range(b_offset, b_size),
623                    /*read_provenance*/ #[allow(non_exhaustive_omitted_patterns)] match b {
    abi::Primitive::Pointer(_) => true,
    _ => false,
}matches!(b, abi::Primitive::Pointer(_)),
624                )?;
625                Some(ImmTy::from_immediate(Immediate::ScalarPair(a_val, b_val), mplace.layout))
626            }
627            _ => {
628                // Neither a scalar nor scalar pair.
629                None
630            }
631        })
632    }
633
634    /// Try returning an immediate for the operand. If the layout does not permit loading this as an
635    /// immediate, return where in memory we can find the data.
636    /// Note that for a given layout, this operation will either always return Left or Right!
637    /// Whether it returns Left depends on whether the layout can be represented
638    /// in an `Immediate`, not on which data is stored there currently.
639    ///
640    /// This is an internal function that should not usually be used; call `read_immediate` instead.
641    /// ConstProp needs it, though.
642    pub fn read_immediate_raw(
643        &self,
644        src: &impl Projectable<'tcx, M::Provenance>,
645    ) -> InterpResult<'tcx, Either<MPlaceTy<'tcx, M::Provenance>, ImmTy<'tcx, M::Provenance>>> {
646        interp_ok(match src.to_op(self)?.as_mplace_or_imm() {
647            Left(ref mplace) => {
648                if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? {
649                    Right(val)
650                } else {
651                    Left(mplace.clone())
652                }
653            }
654            Right(val) => Right(val),
655        })
656    }
657
658    /// Read an immediate from a place, asserting that that is possible with the given layout.
659    ///
660    /// If this succeeds, the `ImmTy` is never `Uninit`.
661    #[inline(always)]
662    pub fn read_immediate(
663        &self,
664        op: &impl Projectable<'tcx, M::Provenance>,
665    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
666        if !#[allow(non_exhaustive_omitted_patterns)] match op.layout().backend_repr {
    BackendRepr::Scalar(abi::Scalar::Initialized { .. }) |
        BackendRepr::ScalarPair {
        a: abi::Scalar::Initialized { .. },
        b: abi::Scalar::Initialized { .. },
        b_offset: _ } => true,
    _ => false,
}matches!(
667            op.layout().backend_repr,
668            BackendRepr::Scalar(abi::Scalar::Initialized { .. })
669                | BackendRepr::ScalarPair {
670                    a: abi::Scalar::Initialized { .. },
671                    b: abi::Scalar::Initialized { .. },
672                    b_offset: _,
673                }
674        ) {
675            ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
    format_args!("primitive read not possible for type: {0}",
        op.layout().ty));span_bug!(self.cur_span(), "primitive read not possible for type: {}", op.layout().ty);
676        }
677        let imm = self.read_immediate_raw(op)?.right().unwrap();
678        if #[allow(non_exhaustive_omitted_patterns)] match *imm {
    Immediate::Uninit => true,
    _ => false,
}matches!(*imm, Immediate::Uninit) {
679            do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::InvalidUninitBytes(None));throw_ub!(InvalidUninitBytes(None));
680        }
681        interp_ok(imm)
682    }
683
684    /// Read a scalar from a place
685    pub fn read_scalar(
686        &self,
687        op: &impl Projectable<'tcx, M::Provenance>,
688    ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
689        interp_ok(self.read_immediate(op)?.to_scalar())
690    }
691
692    // Pointer-sized reads are fairly common and need target layout access, so we wrap them in
693    // convenience functions.
694
695    /// Read a pointer from a place.
696    pub fn read_pointer(
697        &self,
698        op: &impl Projectable<'tcx, M::Provenance>,
699    ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
700        interp_ok(self.read_scalar(op)?.to_pointer(self))
701    }
702    /// Read a pointer-sized unsigned integer from a place.
703    pub fn read_target_usize(
704        &self,
705        op: &impl Projectable<'tcx, M::Provenance>,
706    ) -> InterpResult<'tcx, u64> {
707        self.read_scalar(op)?.to_target_usize(self)
708    }
709    /// Read a pointer-sized signed integer from a place.
710    pub fn read_target_isize(
711        &self,
712        op: &impl Projectable<'tcx, M::Provenance>,
713    ) -> InterpResult<'tcx, i64> {
714        self.read_scalar(op)?.to_target_isize(self)
715    }
716
717    /// Turn the wide MPlace into a string (must already be dereferenced!)
718    pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx, &str> {
719        let len = mplace.len(self)?;
720        let bytes = self.read_bytes_ptr_strip_provenance(mplace.ptr(), Size::from_bytes(len))?;
721        let s = std::str::from_utf8(bytes).map_err(|err| ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::InvalidStr(err))err_ub!(InvalidStr(err)))?;
722        interp_ok(s)
723    }
724
725    /// Read from a local of a current frame.
726    /// Will not access memory, instead an indirect `Operand` is returned.
727    pub fn local_to_op(
728        &self,
729        local: mir::Local,
730        layout: Option<TyAndLayout<'tcx>>,
731    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
732        let frame = self.frame();
733        let layout = self.layout_of_local(frame, local, layout)?;
734        let op = *frame.locals[local].access()?;
735        if #[allow(non_exhaustive_omitted_patterns)] match op {
    Operand::Immediate(_) => true,
    _ => false,
}matches!(op, Operand::Immediate(_)) {
736            if !!layout.is_unsized() {
    ::core::panicking::panic("assertion failed: !layout.is_unsized()")
};assert!(!layout.is_unsized());
737            if !self.validation_in_progress() {
738                M::after_local_read(self, local)?;
739            }
740        }
741        interp_ok(OpTy { op, layout })
742    }
743
744    /// Tools like Priroda and [Aquascope](https://github.com/cognitive-engineering-lab/aquascope/)
745    /// need to access any local without triggering any access hook, since these are not actual
746    /// AM-level accesses. Do not call this from inside the interpreter!
747    ///
748    /// Remember to use `ghost_run` when accessing memory for such purposes, to suppress
749    /// the access hooks for that as well.
750    pub fn ghost_local_in_frame_to_op(
751        &self,
752        frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
753        local: mir::Local,
754    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
755        let layout = self.layout_of_local(frame, local, None)?;
756        let op = *frame.locals[local].access()?;
757        interp_ok(OpTy { op, layout })
758    }
759
760    /// Every place can be read from, so we can turn them into an operand.
761    /// This will definitely return `Indirect` if the place is a `Ptr`, i.e., this
762    /// will never actually read from memory.
763    pub fn place_to_op(
764        &self,
765        place: &PlaceTy<'tcx, M::Provenance>,
766    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
767        match place.as_mplace_or_local() {
768            Left(mplace) => interp_ok(mplace.into()),
769            Right((local, offset, locals_addr, _)) => {
770                if true {
    if !place.layout.is_sized() {
        ::core::panicking::panic("assertion failed: place.layout.is_sized()")
    };
};debug_assert!(place.layout.is_sized()); // only sized locals can ever be `Place::Local`.
771                if true {
    {
        match (&locals_addr, &self.frame().locals_addr()) {
            (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);
                }
            }
        }
    };
};debug_assert_eq!(locals_addr, self.frame().locals_addr());
772                let base = self.local_to_op(local, None)?;
773                interp_ok(match offset {
774                    Some(offset) => base.offset(offset, place.layout, self)?,
775                    None => {
776                        // In the common case this hasn't been projected.
777                        if true {
    {
        match (&place.layout, &base.layout) {
            (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);
                }
            }
        }
    };
};debug_assert_eq!(place.layout, base.layout);
778                        base
779                    }
780                })
781            }
782        }
783    }
784
785    /// Evaluate a place with the goal of reading from it. This lets us sometimes
786    /// avoid allocations.
787    pub fn eval_place_to_op(
788        &self,
789        mir_place: mir::Place<'tcx>,
790        layout: Option<TyAndLayout<'tcx>>,
791    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
792        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("step",
                                "rustc_const_eval::interpret::operand",
                                ::tracing::Level::INFO,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/operand.rs"),
                                ::tracing_core::__macro_support::Option::Some(792u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::operand"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("step")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("step");
                                                    NAME.as_str()
                                                },
                                                {
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("mir_place")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("mir_place");
                                                    NAME.as_str()
                                                },
                                                {
                                                    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()
                                                }], ::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(&"eval_place_to_op")
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&mir_place)
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&Empty as
                                                        &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        })enter_trace_span!(
793            M,
794            step::eval_place_to_op,
795            ?mir_place,
796            tracing_separate_thread = Empty
797        );
798
799        // Do not use the layout passed in as argument if the base we are looking at
800        // here is not the entire place.
801        let layout = if mir_place.projection.is_empty() { layout } else { None };
802
803        let mut op = self.local_to_op(mir_place.local, layout)?;
804        // Using `try_fold` turned out to be bad for performance, hence the loop.
805        for elem in mir_place.projection.iter() {
806            op = self.project(&op, elem)?
807        }
808
809        {
    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/operand.rs:809",
                        "rustc_const_eval::interpret::operand",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/operand.rs"),
                        ::tracing_core::__macro_support::Option::Some(809u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::operand"),
                        ::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!("eval_place_to_op: got {0:?}",
                                                    op) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};trace!("eval_place_to_op: got {:?}", op);
810        // Sanity-check the type we ended up with.
811        if truecfg!(debug_assertions) {
812            let normalized_place_ty = self
813                .instantiate_from_current_frame_and_normalize_erasing_regions(
814                    mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
815                )?;
816            if !mir_assign_valid_types(
817                *self.tcx,
818                self.typing_env(),
819                self.layout_of(normalized_place_ty)?,
820                op.layout,
821            ) {
822                ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
    format_args!("eval_place of a MIR place with type {0} produced an interpreter operand with type {1}",
        normalized_place_ty, op.layout.ty))span_bug!(
823                    self.cur_span(),
824                    "eval_place of a MIR place with type {} produced an interpreter operand with type {}",
825                    normalized_place_ty,
826                    op.layout.ty,
827                )
828            }
829        }
830        interp_ok(op)
831    }
832
833    /// Evaluate the operand, returning a place where you can then find the data.
834    /// If you already know the layout, you can save two table lookups
835    /// by passing it in here.
836    #[inline]
837    pub fn eval_operand(
838        &self,
839        mir_op: &mir::Operand<'tcx>,
840        layout: Option<TyAndLayout<'tcx>>,
841    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
842        let _trace =
843            <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("step",
                                "rustc_const_eval::interpret::operand",
                                ::tracing::Level::INFO,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/operand.rs"),
                                ::tracing_core::__macro_support::Option::Some(843u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::operand"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("step")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("step");
                                                    NAME.as_str()
                                                },
                                                {
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("mir_op")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("mir_op");
                                                    NAME.as_str()
                                                },
                                                {
                                                    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()
                                                }], ::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(&"eval_operand")
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&mir_op)
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&Empty as
                                                        &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        })enter_trace_span!(M, step::eval_operand, ?mir_op, tracing_separate_thread = Empty);
844
845        use rustc_middle::mir::Operand::*;
846        let op = match mir_op {
847            // FIXME: do some more logic on `move` to invalidate the old location
848            &Copy(place) | &Move(place) => self.eval_place_to_op(place, layout)?,
849
850            &RuntimeChecks(checks) => {
851                let val = M::runtime_checks(self, checks)?;
852                ImmTy::from_bool(val, self.tcx()).into()
853            }
854
855            Constant(constant) => {
856                let c = self.instantiate_from_current_frame_and_normalize_erasing_regions(
857                    constant.const_,
858                )?;
859
860                // This can still fail:
861                // * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
862                //   checked yet.
863                // * During CTFE, since promoteds in `const`/`static` initializer bodies can fail.
864                self.eval_mir_constant(&c, constant.span, layout)?
865            }
866        };
867        {
    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/operand.rs:867",
                        "rustc_const_eval::interpret::operand",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/a69a63265cfd9e006d43137f98301b8d274ad4c9/compiler/rustc_const_eval/src/interpret/operand.rs"),
                        ::tracing_core::__macro_support::Option::Some(867u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::operand"),
                        ::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:?}: {1:?}",
                                                    mir_op, op) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};trace!("{:?}: {:?}", mir_op, op);
868        interp_ok(op)
869    }
870
871    pub(crate) fn const_val_to_op(
872        &self,
873        val_val: mir::ConstValue,
874        ty: Ty<'tcx>,
875        layout: Option<TyAndLayout<'tcx>>,
876    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
877        // Other cases need layout.
878        let adjust_scalar = |scalar| -> InterpResult<'tcx, _> {
879            interp_ok(match scalar {
880                Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_root_pointer(ptr)?, size),
881                Scalar::Int(int) => Scalar::Int(int),
882            })
883        };
884        let layout =
885            from_known_layout(self.tcx, self.typing_env(), layout, || self.layout_of(ty).into())?;
886        let imm = match val_val {
887            mir::ConstValue::Indirect { alloc_id, offset } => {
888                // This is const data, no mutation allowed.
889                let ptr = self.global_root_pointer(Pointer::new(
890                    CtfeProvenance::from(alloc_id).as_immutable(),
891                    offset,
892                ))?;
893                return interp_ok(self.ptr_to_mplace(ptr.into(), layout).into());
894            }
895            mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(),
896            mir::ConstValue::ZeroSized => Immediate::Uninit,
897            mir::ConstValue::Slice { alloc_id, meta } => {
898                // This is const data, no mutation allowed.
899                let ptr = Pointer::new(CtfeProvenance::from(alloc_id).as_immutable(), Size::ZERO);
900                Immediate::new_slice(self.global_root_pointer(ptr)?.into(), meta, self)
901            }
902        };
903        interp_ok(OpTy { op: Operand::Immediate(imm), layout })
904    }
905}
906
907// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
908#[cfg(target_pointer_width = "64")]
909mod size_asserts {
910    use rustc_data_structures::static_assert_size;
911
912    use super::*;
913    // tidy-alphabetical-start
914    const _: [(); 64] = [(); ::std::mem::size_of::<ImmTy<'_>>()];static_assert_size!(ImmTy<'_>, 64);
915    const _: [(); 48] = [(); ::std::mem::size_of::<Immediate>()];static_assert_size!(Immediate, 48);
916    const _: [(); 72] = [(); ::std::mem::size_of::<OpTy<'_>>()];static_assert_size!(OpTy<'_>, 72);
917    const _: [(); 56] = [(); ::std::mem::size_of::<Operand>()];static_assert_size!(Operand, 56);
918    // tidy-alphabetical-end
919}