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.
910use std::marker::PhantomData;
11use std::ops::Range;
1213use rustc_abi::{selfas 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};
1920use super::{
21InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar, err_ub,
22interp_ok, throw_ub, throw_unsup,
23};
2425/// 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`.
29Inbounds,
30/// No constraints, just wrap around the edge of the address space.
31Wrapping,
32}
3334/// 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.
37fn layout(&self) -> TyAndLayout<'tcx>;
3839/// Get the metadata of a wide value.
40fn meta(&self) -> MemPlaceMeta<Prov>;
4142/// Get the length of a slice/string/array stored here.
43fn len<M: Machine<'tcx, Provenance = Prov>>(
44&self,
45 ecx: &InterpCx<'tcx, M>,
46 ) -> InterpResult<'tcx, u64> {
47let layout = self.layout();
48if layout.is_unsized() {
49// We need to consult `meta` metadata
50match 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!)
57match 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 }
6364/// Offset the value by the given amount, replacing the layout and metadata.
65fn 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>;
7374fn offset<M: Machine<'tcx, Provenance = Prov>>(
75&self,
76 offset: Size,
77 layout: TyAndLayout<'tcx>,
78 ecx: &InterpCx<'tcx, M>,
79 ) -> InterpResult<'tcx, Self> {
80if !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.
83self.offset_with_meta(offset, OffsetMode::Inbounds, MemPlaceMeta::None, layout, ecx)
84 }
8586/// 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).
90fn transmute<M: Machine<'tcx, Provenance = Prov>>(
91&self,
92 layout: TyAndLayout<'tcx>,
93 ecx: &InterpCx<'tcx, M>,
94 ) -> InterpResult<'tcx, Self> {
95if !(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());
96match (&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);
97self.offset_with_meta(Size::ZERO, OffsetMode::Wrapping, MemPlaceMeta::None, layout, ecx)
98 }
99100/// 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!
102fn to_op<M: Machine<'tcx, Provenance = Prov>>(
103&self,
104 ecx: &InterpCx<'tcx, M>,
105 ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>;
106}
107108/// 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}
116117impl<'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.
119pub fn next<M: Machine<'tcx, Provenance = Prov>>(
120&mut self,
121 ecx: &InterpCx<'tcx, M>,
122 ) -> InterpResult<'tcx, Option<(u64, P)>> {
123let 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.
125interp_ok(Some((
126idx,
127self.base.offset_with_meta(
128self.stride * idx,
129 OffsetMode::Wrapping,
130 MemPlaceMeta::None,
131self.field_layout,
132 ecx,
133 )?,
134 )))
135 }
136}
137138// FIXME: Working around https://github.com/rust-lang/rust/issues/54385
139impl<'tcx, Prov, M> InterpCx<'tcx, M>
140where
141Prov: 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`].
150pub 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`.
156if 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);
160let 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).
163let field_layout = base.layout().field(self, field.as_usize());
164165// Offset may need adjustment for unsized fields.
166let (meta, offset) = if field_layout.is_unsized() {
167if !!base.layout().is_sized() {
::core::panicking::panic("assertion failed: !base.layout().is_sized()")
};assert!(!base.layout().is_sized());
168let 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.
172match self.size_and_align_from_meta(&base_meta, &field_layout)? {
173Some((_, align)) => {
174// For packed types, we need to cap alignment.
175let align = if let ty::Adt(def, _) = base.layout().ty.kind()
176 && let Some(packed) = def.repr().pack
177 {
178align.min(packed)
179 } else {
180align181 };
182 (base_meta, offset.align_to(align))
183 }
184Noneif 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 }
189None => {
190// We cannot know the alignment of this field, so we cannot adjust.
191do 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 };
199200base.offset_with_meta(offset, OffsetMode::Inbounds, meta, field_layout, self)
201 }
202203/// Projects multiple fields at once. See [`Self::project_field`] for details.
204pub 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]> {
209fields.try_map(|field| self.project_field(base, field))
210 }
211212/// Downcasting to an enum variant.
213pub fn project_downcast<P: Projectable<'tcx, M::Provenance>>(
214&self,
215 base: &P,
216 variant: VariantIdx,
217 ) -> InterpResult<'tcx, P> {
218if !!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.
223let 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>.
226227 // This cannot be `transmute` as variants *can* have a smaller size than the entire enum.
228base.offset(Size::ZERO, layout, self)
229 }
230231/// Equivalent to `project_downcast`, but identifies the variant by name instead of index.
232pub fn project_downcast_named<P: Projectable<'tcx, M::Provenance>>(
233&self,
234 base: &P,
235 name: Symbol,
236 ) -> InterpResult<'tcx, (VariantIdx, P)> {
237let variants = base.layout().ty.ty_adt_def().unwrap().variants();
238let variant_idx = variants239 .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;
243244interp_ok((variant_idx, self.project_downcast(base, variant_idx)?))
245 }
246247/// Compute the offset and field layout for accessing the given index.
248pub 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
254let (offset, field_layout) = match base.layout().fields {
255 abi::FieldsShape::Array { stride, count: _ } => {
256// `count` is nonsense for slices, use the dynamic length instead.
257let len = base.len(self)?;
258if index >= len {
259// This can only be reached in ConstProp and non-rustc-MIR.
260do 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.
263let 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))?;
266267// All fields have the same layout.
268let 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!(
272self.cur_span(),
273"`project_index` called on non-array type {:?}",
274 base.layout().ty
275 ),
276 };
277278base.offset(offset, field_layout, self)
279 }
280281/// 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.
283pub fn project_to_simd<P: Projectable<'tcx, M::Provenance>>(
284&self,
285 base: &P,
286 ) -> InterpResult<'tcx, (P, u64)> {
287if !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.
289let array = self.project_field(base, FieldIdx::ZERO)?;
290let len = array.len(self)?;
291interp_ok((array, len))
292 }
293294fn 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> {
301let n = base.len(self)?;
302if n < min_length {
303// This can only be reached in ConstProp and non-rustc-MIR.
304do 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 }
306307let index = if from_end {
308if !(0 < offset && offset <= min_length) {
::core::panicking::panic("assertion failed: 0 < offset && offset <= min_length")
};assert!(0 < offset && offset <= min_length);
309n.checked_sub(offset).unwrap()
310 } else {
311if !(offset < min_length) {
::core::panicking::panic("assertion failed: offset < min_length")
};assert!(offset < min_length);
312offset313 };
314315self.project_index(base, index)
316 }
317318/// Iterates over all fields of an array. Much more efficient than doing the
319 /// same by repeatedly calling `project_index`.
320pub 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>> {
324let 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!(
326self.cur_span(),
327"project_array_fields: expected an array layout, got {:#?}",
328 base.layout()
329 );
330 };
331let len = base.len(self)?;
332let 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.
337interp_ok(ArrayIterator {
338base,
339 range: 0..len,
340stride,
341field_layout,
342 _phantom: PhantomData,
343 })
344 }
345346/// Subslicing
347fn 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> {
354let len = base.len(self)?; // also asserts that we have a type where this makes sense
355let actual_to = if from_end {
356if from.checked_add(to).is_none_or(|to| to > len) {
357// This can only be reached in ConstProp and non-rustc-MIR.
358do 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 }
360len.checked_sub(to).unwrap()
361 } else {
362to363 };
364365// Not using layout method because that works with usize, and does not work with slices
366 // (that have count 0 in their layout).
367let 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!(
371self.cur_span(),
372"unexpected layout of index access: {:#?}",
373 base.layout()
374 )375 }
376 };
377378// Compute meta and new layout
379let inner_len = actual_to.checked_sub(from).unwrap();
380let (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.
383ty::Array(inner, _) => {
384 (MemPlaceMeta::None, Ty::new_array(self.tcx.tcx, *inner, inner_len))
385 }
386 ty::Slice(..) => {
387let 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!(
392self.cur_span(),
393"cannot subslice non-array type: `{:?}`",
394 base.layout().ty
395 )396 }
397 };
398let layout = self.layout_of(ty)?;
399400base.offset_with_meta(from_offset, OffsetMode::Inbounds, meta, layout, self)
401 }
402403/// 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")]405pub fn project<P>(&self, base: &P, proj_elem: mir::PlaceElem<'tcx>) -> InterpResult<'tcx, P>
406where
407P: Projectable<'tcx, M::Provenance> + From<MPlaceTy<'tcx, M::Provenance>> + std::fmt::Debug,
408 {
409use rustc_middle::mir::ProjectionElem::*;
410 interp_ok(match proj_elem {
411 OpaqueCast(ty) => {
412span_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) => {
419let layout = self.layout_of(self.tcx.types.usize)?;
420let n = self.local_to_op(local, Some(layout))?;
421let n = self.read_target_usize(&n)?;
422self.project_index(base, n)?
423}
424 ConstantIndex { offset, min_length, from_end } => {
425self.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}