Skip to main content

rustc_const_eval/interpret/
projection.rs

1//! This file implements "place projections"; basically a symmetric API for 3 types: MPlaceTy, OpTy, PlaceTy.
2//!
3//! OpTy and PlaceTy generally work by "let's see if we are actually an MPlaceTy, and do something custom if not".
4//! For PlaceTy, the custom thing is basically always to call `force_allocation` and then use the MPlaceTy logic anyway.
5//! For OpTy, the custom thing on field projections has to be pretty clever (since `Operand::Immediate` can have fields),
6//! but for array/slice operations it only has to worry about `Operand::Uninit`. That makes the value part trivial,
7//! but we still need to do bounds checking and adjust the layout. To not duplicate that with MPlaceTy, we actually
8//! implement the logic on OpTy, and MPlaceTy calls that.
9
10use std::marker::PhantomData;
11use std::ops::Range;
12
13use rustc_abi::{self as abi, FieldIdx, Size, VariantIdx};
14use rustc_middle::ty::Ty;
15use rustc_middle::ty::layout::TyAndLayout;
16use rustc_middle::{bug, mir, span_bug, ty};
17use rustc_span::Symbol;
18use tracing::{debug, instrument};
19
20use super::{
21    InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar, err_ub,
22    interp_ok, throw_ub, throw_unsup,
23};
24
25/// Describes the constraints placed on offset-projections.
26#[derive(#[automatically_derived]
impl ::core::marker::Copy for OffsetMode { }Copy, #[automatically_derived]
impl ::core::clone::Clone for OffsetMode {
    #[inline]
    fn clone(&self) -> OffsetMode { *self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for OffsetMode {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                OffsetMode::Inbounds => "Inbounds",
                OffsetMode::Wrapping => "Wrapping",
            })
    }
}Debug)]
27pub enum OffsetMode {
28    /// The offset has to be inbounds, like `ptr::offset`.
29    Inbounds,
30    /// No constraints, just wrap around the edge of the address space.
31    Wrapping,
32}
33
34/// A thing that we can project into, and that has a layout.
35pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug {
36    /// Get the layout.
37    fn layout(&self) -> TyAndLayout<'tcx>;
38
39    /// Get the metadata of a wide value.
40    fn meta(&self) -> MemPlaceMeta<Prov>;
41
42    /// Get the length of a slice/string/array stored here.
43    fn len<M: Machine<'tcx, Provenance = Prov>>(
44        &self,
45        ecx: &InterpCx<'tcx, M>,
46    ) -> InterpResult<'tcx, u64> {
47        let layout = self.layout();
48        if layout.is_unsized() {
49            // We need to consult `meta` metadata
50            match layout.ty.kind() {
51                ty::Slice(..) | ty::Str => self.meta().unwrap_meta().to_target_usize(ecx),
52                _ => ::rustc_middle::util::bug::bug_fmt(format_args!("len not supported on unsized type {0:?}",
        layout.ty))bug!("len not supported on unsized type {:?}", layout.ty),
53            }
54        } else {
55            // Go through the layout. There are lots of types that support a length,
56            // e.g., SIMD types. (But not all repr(simd) types even have FieldsShape::Array!)
57            match layout.fields {
58                abi::FieldsShape::Array { count, .. } => interp_ok(count),
59                _ => ::rustc_middle::util::bug::bug_fmt(format_args!("len not supported on sized type {0:?}",
        layout.ty))bug!("len not supported on sized type {:?}", layout.ty),
60            }
61        }
62    }
63
64    /// Offset the value by the given amount, replacing the layout and metadata.
65    fn offset_with_meta<M: Machine<'tcx, Provenance = Prov>>(
66        &self,
67        offset: Size,
68        mode: OffsetMode,
69        meta: MemPlaceMeta<Prov>,
70        layout: TyAndLayout<'tcx>,
71        ecx: &InterpCx<'tcx, M>,
72    ) -> InterpResult<'tcx, Self>;
73
74    fn offset<M: Machine<'tcx, Provenance = Prov>>(
75        &self,
76        offset: Size,
77        layout: TyAndLayout<'tcx>,
78        ecx: &InterpCx<'tcx, M>,
79    ) -> InterpResult<'tcx, Self> {
80        if !layout.is_sized() {
    ::core::panicking::panic("assertion failed: layout.is_sized()")
};assert!(layout.is_sized());
81        // We sometimes do pointer arithmetic with this function, disregarding the source type.
82        // So we don't check the sizes here.
83        self.offset_with_meta(offset, OffsetMode::Inbounds, MemPlaceMeta::None, layout, ecx)
84    }
85
86    /// This does an offset-by-zero, which is effectively a transmute. Note however that
87    /// not all transmutes are supported by all projectables -- specifically, if this is an
88    /// `OpTy` or `ImmTy`, the new layout must have almost the same ABI as the old one
89    /// (only changing the `valid_range` is allowed and turning integers into pointers).
90    fn transmute<M: Machine<'tcx, Provenance = Prov>>(
91        &self,
92        layout: TyAndLayout<'tcx>,
93        ecx: &InterpCx<'tcx, M>,
94    ) -> InterpResult<'tcx, Self> {
95        if !(self.layout().is_sized() && layout.is_sized()) {
    ::core::panicking::panic("assertion failed: self.layout().is_sized() && layout.is_sized()")
};assert!(self.layout().is_sized() && layout.is_sized());
96        match (&self.layout().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);
        }
    }
};assert_eq!(self.layout().size, layout.size);
97        self.offset_with_meta(Size::ZERO, OffsetMode::Wrapping, MemPlaceMeta::None, layout, ecx)
98    }
99
100    /// Convert this to an `OpTy`. This might be an irreversible transformation, but is useful for
101    /// reading from this thing. This will never actually do a read from memory!
102    fn to_op<M: Machine<'tcx, Provenance = Prov>>(
103        &self,
104        ecx: &InterpCx<'tcx, M>,
105    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>;
106}
107
108/// A type representing iteration over the elements of an array.
109pub struct ArrayIterator<'a, 'tcx, Prov: Provenance, P: Projectable<'tcx, Prov>> {
110    base: &'a P,
111    range: Range<u64>,
112    stride: Size,
113    field_layout: TyAndLayout<'tcx>,
114    _phantom: PhantomData<Prov>, // otherwise it says `Prov` is never used...
115}
116
117impl<'a, 'tcx, Prov: Provenance, P: Projectable<'tcx, Prov>> ArrayIterator<'a, 'tcx, Prov, P> {
118    /// Should be the same `ecx` on each call, and match the one used to create the iterator.
119    pub fn next<M: Machine<'tcx, Provenance = Prov>>(
120        &mut self,
121        ecx: &InterpCx<'tcx, M>,
122    ) -> InterpResult<'tcx, Option<(u64, P)>> {
123        let Some(idx) = self.range.next() else { return interp_ok(None) };
124        // We use `Wrapping` here since the offset has already been checked when the iterator was created.
125        interp_ok(Some((
126            idx,
127            self.base.offset_with_meta(
128                self.stride * idx,
129                OffsetMode::Wrapping,
130                MemPlaceMeta::None,
131                self.field_layout,
132                ecx,
133            )?,
134        )))
135    }
136}
137
138// FIXME: Working around https://github.com/rust-lang/rust/issues/54385
139impl<'tcx, Prov, M> InterpCx<'tcx, M>
140where
141    Prov: Provenance,
142    M: Machine<'tcx, Provenance = Prov>,
143{
144    /// Offset a pointer to project to a field of a struct/union. Unlike `place_field`, this is
145    /// always possible without allocating, so it can take `&self`. Also return the field's layout.
146    /// This supports both struct and array fields, but not slices!
147    ///
148    /// This also works for arrays, but then the `FieldIdx` index type is restricting.
149    /// For indexing into arrays, use [`Self::project_index`].
150    pub fn project_field<P: Projectable<'tcx, M::Provenance>>(
151        &self,
152        base: &P,
153        field: FieldIdx,
154    ) -> InterpResult<'tcx, P> {
155        // Slices nominally have length 0, so they will panic somewhere in `fields.offset`.
156        if true {
    if !!#[allow(non_exhaustive_omitted_patterns)] match base.layout().ty.kind()
                    {
                    ty::Slice(..) => true,
                    _ => false,
                } {
        {
            ::core::panicking::panic_fmt(format_args!("`field` projection called on a slice -- call `index` projection instead"));
        }
    };
};debug_assert!(
157            !matches!(base.layout().ty.kind(), ty::Slice(..)),
158            "`field` projection called on a slice -- call `index` projection instead"
159        );
160        let offset = base.layout().fields.offset(field.as_usize());
161        // Computing the layout does normalization, so we get a normalized type out of this
162        // even if the field type is non-normalized (possible e.g. via associated types).
163        let field_layout = base.layout().field(self, field.as_usize());
164
165        // Offset may need adjustment for unsized fields.
166        let (meta, offset) = if field_layout.is_unsized() {
167            if !!base.layout().is_sized() {
    ::core::panicking::panic("assertion failed: !base.layout().is_sized()")
};assert!(!base.layout().is_sized());
168            let base_meta = base.meta();
169            // Re-use parent metadata to determine dynamic field layout.
170            // With custom DSTS, this *will* execute user-defined code, but the same
171            // happens at run-time so that's okay.
172            match self.size_and_align_from_meta(&base_meta, &field_layout)? {
173                Some((_, align)) => {
174                    // For packed types, we need to cap alignment.
175                    let align = if let ty::Adt(def, _) = base.layout().ty.kind()
176                        && let Some(packed) = def.repr().pack
177                    {
178                        align.min(packed)
179                    } else {
180                        align
181                    };
182                    (base_meta, offset.align_to(align))
183                }
184                None if offset == Size::ZERO => {
185                    // If the offset is 0, then rounding it up to alignment wouldn't change anything,
186                    // so we can do this even for types where we cannot determine the alignment.
187                    (base_meta, offset)
188                }
189                None => {
190                    // We cannot know the alignment of this field, so we cannot adjust.
191                    do yeet ::rustc_middle::mir::interpret::InterpErrorKind::Unsupported(::rustc_middle::mir::interpret::UnsupportedOpInfo::ExternTypeField)throw_unsup!(ExternTypeField)
192                }
193            }
194        } else {
195            // base_meta could be present; we might be accessing a sized field of an unsized
196            // struct.
197            (MemPlaceMeta::None, offset)
198        };
199
200        base.offset_with_meta(offset, OffsetMode::Inbounds, meta, field_layout, self)
201    }
202
203    /// Projects multiple fields at once. See [`Self::project_field`] for details.
204    pub fn project_fields<P: Projectable<'tcx, M::Provenance>, const N: usize>(
205        &self,
206        base: &P,
207        fields: [FieldIdx; N],
208    ) -> InterpResult<'tcx, [P; N]> {
209        fields.try_map(|field| self.project_field(base, field))
210    }
211
212    /// Downcasting to an enum variant.
213    pub fn project_downcast<P: Projectable<'tcx, M::Provenance>>(
214        &self,
215        base: &P,
216        variant: VariantIdx,
217    ) -> InterpResult<'tcx, P> {
218        if !!base.meta().has_meta() {
    ::core::panicking::panic("assertion failed: !base.meta().has_meta()")
};assert!(!base.meta().has_meta());
219        // Downcasts only change the layout.
220        // (In particular, no check about whether this is even the active variant -- that's by design,
221        // see https://github.com/rust-lang/rust/issues/93688#issuecomment-1032929496.)
222        // So we just "offset" by 0.
223        let layout = base.layout().for_variant(self, variant);
224        // This variant may in fact be uninhabited.
225        // See <https://github.com/rust-lang/rust/issues/120337>.
226
227        // This cannot be `transmute` as variants *can* have a smaller size than the entire enum.
228        base.offset(Size::ZERO, layout, self)
229    }
230
231    /// Equivalent to `project_downcast`, but identifies the variant by name instead of index.
232    pub fn project_downcast_named<P: Projectable<'tcx, M::Provenance>>(
233        &self,
234        base: &P,
235        name: Symbol,
236    ) -> InterpResult<'tcx, (VariantIdx, P)> {
237        let variants = base.layout().ty.ty_adt_def().unwrap().variants();
238        let variant_idx = variants
239            .iter_enumerated()
240            .find(|(_idx, var)| var.name == name)
241            .unwrap_or_else(|| {
    ::core::panicking::panic_fmt(format_args!("got {0} but expected one of {1:#?}",
            name, variants));
}panic!("got {name} but expected one of {variants:#?}"))
242            .0;
243
244        interp_ok((variant_idx, self.project_downcast(base, variant_idx)?))
245    }
246
247    /// Compute the offset and field layout for accessing the given index.
248    pub fn project_index<P: Projectable<'tcx, M::Provenance>>(
249        &self,
250        base: &P,
251        index: u64,
252    ) -> InterpResult<'tcx, P> {
253        // Not using the layout method because we want to compute on u64
254        let (offset, field_layout) = match base.layout().fields {
255            abi::FieldsShape::Array { stride, count: _ } => {
256                // `count` is nonsense for slices, use the dynamic length instead.
257                let len = base.len(self)?;
258                if index >= len {
259                    // This can only be reached in ConstProp and non-rustc-MIR.
260                    do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::BoundsCheckFailed {
            len,
            index,
        });throw_ub!(BoundsCheckFailed { len, index });
261                }
262                // With raw slices, `len` can be so big that this *can* overflow.
263                let offset = self
264                    .compute_size_in_bytes(stride, index)
265                    .ok_or_else(|| ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::PointerArithOverflow)err_ub!(PointerArithOverflow))?;
266
267                // All fields have the same layout.
268                let field_layout = base.layout().field(self, 0);
269                (offset, field_layout)
270            }
271            _ => ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
    format_args!("`project_index` called on non-array type {0:?}",
        base.layout().ty))span_bug!(
272                self.cur_span(),
273                "`project_index` called on non-array type {:?}",
274                base.layout().ty
275            ),
276        };
277
278        base.offset(offset, field_layout, self)
279    }
280
281    /// Converts a repr(simd) value into an array of the right size, such that `project_index`
282    /// accesses the SIMD elements. Also returns the number of elements.
283    pub fn project_to_simd<P: Projectable<'tcx, M::Provenance>>(
284        &self,
285        base: &P,
286    ) -> InterpResult<'tcx, (P, u64)> {
287        if !base.layout().ty.ty_adt_def().unwrap().repr().simd() {
    ::core::panicking::panic("assertion failed: base.layout().ty.ty_adt_def().unwrap().repr().simd()")
};assert!(base.layout().ty.ty_adt_def().unwrap().repr().simd());
288        // SIMD types must be newtypes around arrays, so all we have to do is project to their only field.
289        let array = self.project_field(base, FieldIdx::ZERO)?;
290        let len = array.len(self)?;
291        interp_ok((array, len))
292    }
293
294    fn project_constant_index<P: Projectable<'tcx, M::Provenance>>(
295        &self,
296        base: &P,
297        offset: u64,
298        min_length: u64,
299        from_end: bool,
300    ) -> InterpResult<'tcx, P> {
301        let n = base.len(self)?;
302        if n < min_length {
303            // This can only be reached in ConstProp and non-rustc-MIR.
304            do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::BoundsCheckFailed {
            len: min_length,
            index: n,
        });throw_ub!(BoundsCheckFailed { len: min_length, index: n });
305        }
306
307        let index = if from_end {
308            if !(0 < offset && offset <= min_length) {
    ::core::panicking::panic("assertion failed: 0 < offset && offset <= min_length")
};assert!(0 < offset && offset <= min_length);
309            n.checked_sub(offset).unwrap()
310        } else {
311            if !(offset < min_length) {
    ::core::panicking::panic("assertion failed: offset < min_length")
};assert!(offset < min_length);
312            offset
313        };
314
315        self.project_index(base, index)
316    }
317
318    /// Iterates over all fields of an array. Much more efficient than doing the
319    /// same by repeatedly calling `project_index`.
320    pub fn project_array_fields<'a, P: Projectable<'tcx, M::Provenance>>(
321        &self,
322        base: &'a P,
323    ) -> InterpResult<'tcx, ArrayIterator<'a, 'tcx, M::Provenance, P>> {
324        let abi::FieldsShape::Array { stride, .. } = base.layout().fields else {
325            ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
    format_args!("project_array_fields: expected an array layout, got {0:#?}",
        base.layout()));span_bug!(
326                self.cur_span(),
327                "project_array_fields: expected an array layout, got {:#?}",
328                base.layout()
329            );
330        };
331        let len = base.len(self)?;
332        let field_layout = base.layout().field(self, 0);
333        // Ensure that all the offsets are in-bounds once, up-front.
334        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_const_eval/src/interpret/projection.rs:334",
                        "rustc_const_eval::interpret::projection",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/interpret/projection.rs"),
                        ::tracing_core::__macro_support::Option::Some(334u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::projection"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::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};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("project_array_fields: {0:?} {1}",
                                                    base, len) as &dyn Value))])
            });
    } else { ; }
};debug!("project_array_fields: {base:?} {len}");
335        base.offset(len * stride, self.layout_of(self.tcx.types.unit).unwrap(), self)?;
336        // Create the iterator.
337        interp_ok(ArrayIterator {
338            base,
339            range: 0..len,
340            stride,
341            field_layout,
342            _phantom: PhantomData,
343        })
344    }
345
346    /// Subslicing
347    fn project_subslice<P: Projectable<'tcx, M::Provenance>>(
348        &self,
349        base: &P,
350        from: u64,
351        to: u64,
352        from_end: bool,
353    ) -> InterpResult<'tcx, P> {
354        let len = base.len(self)?; // also asserts that we have a type where this makes sense
355        let actual_to = if from_end {
356            if from.checked_add(to).is_none_or(|to| to > len) {
357                // This can only be reached in ConstProp and non-rustc-MIR.
358                do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::BoundsCheckFailed {
            len,
            index: from.saturating_add(to),
        });throw_ub!(BoundsCheckFailed { len, index: from.saturating_add(to) });
359            }
360            len.checked_sub(to).unwrap()
361        } else {
362            to
363        };
364
365        // Not using layout method because that works with usize, and does not work with slices
366        // (that have count 0 in their layout).
367        let from_offset = match base.layout().fields {
368            abi::FieldsShape::Array { stride, .. } => stride * from, // `Size` multiplication is checked
369            _ => {
370                ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
    format_args!("unexpected layout of index access: {0:#?}", base.layout()))span_bug!(
371                    self.cur_span(),
372                    "unexpected layout of index access: {:#?}",
373                    base.layout()
374                )
375            }
376        };
377
378        // Compute meta and new layout
379        let inner_len = actual_to.checked_sub(from).unwrap();
380        let (meta, ty) = match base.layout().ty.kind() {
381            // It is not nice to match on the type, but that seems to be the only way to
382            // implement this.
383            ty::Array(inner, _) => {
384                (MemPlaceMeta::None, Ty::new_array(self.tcx.tcx, *inner, inner_len))
385            }
386            ty::Slice(..) => {
387                let len = Scalar::from_target_usize(inner_len, self);
388                (MemPlaceMeta::Meta(len), base.layout().ty)
389            }
390            _ => {
391                ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
    format_args!("cannot subslice non-array type: `{0:?}`", base.layout().ty))span_bug!(
392                    self.cur_span(),
393                    "cannot subslice non-array type: `{:?}`",
394                    base.layout().ty
395                )
396            }
397        };
398        let layout = self.layout_of(ty)?;
399
400        base.offset_with_meta(from_offset, OffsetMode::Inbounds, meta, layout, self)
401    }
402
403    /// Applying a general projection
404    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::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("project",
                                    "rustc_const_eval::interpret::projection",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/interpret/projection.rs"),
                                    ::tracing_core::__macro_support::Option::Some(404u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::projection"),
                                    ::tracing_core::field::FieldSet::new(&["base", "proj_elem"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::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};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&base)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&proj_elem)
                                                            as &dyn 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, P> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            use rustc_middle::mir::ProjectionElem::*;
            interp_ok(match proj_elem {
                    OpaqueCast(ty) => {
                        ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
                            format_args!("OpaqueCast({0}) encountered after borrowck",
                                ty))
                    }
                    UnwrapUnsafeBinder(target) =>
                        base.transmute(self.layout_of(target)?, self)?,
                    Field(field, _) => self.project_field(base, field)?,
                    Downcast(_, variant) =>
                        self.project_downcast(base, variant)?,
                    Deref => self.deref_pointer(&base.to_op(self)?)?.into(),
                    Index(local) => {
                        let layout = self.layout_of(self.tcx.types.usize)?;
                        let n = self.local_to_op(local, Some(layout))?;
                        let n = self.read_target_usize(&n)?;
                        self.project_index(base, n)?
                    }
                    ConstantIndex { offset, min_length, from_end } => {
                        self.project_constant_index(base, offset, min_length,
                                from_end)?
                    }
                    Subslice { from, to, from_end } =>
                        self.project_subslice(base, from, to, from_end)?,
                })
        }
    }
}#[instrument(skip(self), level = "trace")]
405    pub fn project<P>(&self, base: &P, proj_elem: mir::PlaceElem<'tcx>) -> InterpResult<'tcx, P>
406    where
407        P: Projectable<'tcx, M::Provenance> + From<MPlaceTy<'tcx, M::Provenance>> + std::fmt::Debug,
408    {
409        use rustc_middle::mir::ProjectionElem::*;
410        interp_ok(match proj_elem {
411            OpaqueCast(ty) => {
412                span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
413            }
414            UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?,
415            Field(field, _) => self.project_field(base, field)?,
416            Downcast(_, variant) => self.project_downcast(base, variant)?,
417            Deref => self.deref_pointer(&base.to_op(self)?)?.into(),
418            Index(local) => {
419                let layout = self.layout_of(self.tcx.types.usize)?;
420                let n = self.local_to_op(local, Some(layout))?;
421                let n = self.read_target_usize(&n)?;
422                self.project_index(base, n)?
423            }
424            ConstantIndex { offset, min_length, from_end } => {
425                self.project_constant_index(base, offset, min_length, from_end)?
426            }
427            Subslice { from, to, from_end } => self.project_subslice(base, from, to, from_end)?,
428        })
429    }
430}