2022-07-04 07:48:05 -05:00
|
|
|
//! This file implements "place projections"; basically a symmetric API for 3 types: MPlaceTy, OpTy, PlaceTy.
|
|
|
|
//!
|
2022-08-17 21:13:37 -05:00
|
|
|
//! OpTy and PlaceTy generally work by "let's see if we are actually an MPlaceTy, and do something custom if not".
|
2022-07-04 07:48:05 -05:00
|
|
|
//! For PlaceTy, the custom thing is basically always to call `force_allocation` and then use the MPlaceTy logic anyway.
|
|
|
|
//! For OpTy, the custom thing on field pojections has to be pretty clever (since `Operand::Immediate` can have fields),
|
|
|
|
//! but for array/slice operations it only has to worry about `Operand::Uninit`. That makes the value part trivial,
|
|
|
|
//! but we still need to do bounds checking and adjust the layout. To not duplicate that with MPlaceTy, we actually
|
|
|
|
//! implement the logic on OpTy, and MPlaceTy calls that.
|
|
|
|
|
2022-11-18 03:18:32 -06:00
|
|
|
use either::{Left, Right};
|
|
|
|
|
2022-07-04 07:48:05 -05:00
|
|
|
use rustc_middle::mir;
|
|
|
|
use rustc_middle::ty;
|
|
|
|
use rustc_middle::ty::layout::LayoutOf;
|
|
|
|
use rustc_target::abi::{self, Abi, VariantIdx};
|
|
|
|
|
|
|
|
use super::{
|
|
|
|
ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, PlaceTy,
|
|
|
|
Provenance, Scalar,
|
|
|
|
};
|
|
|
|
|
|
|
|
// FIXME: Working around https://github.com/rust-lang/rust/issues/54385
|
2022-07-18 17:47:31 -05:00
|
|
|
impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M>
|
2022-07-04 07:48:05 -05:00
|
|
|
where
|
2022-08-27 13:54:02 -05:00
|
|
|
Prov: Provenance + 'static,
|
2022-07-18 17:47:31 -05:00
|
|
|
M: Machine<'mir, 'tcx, Provenance = Prov>,
|
2022-07-04 07:48:05 -05:00
|
|
|
{
|
|
|
|
//# Field access
|
|
|
|
|
|
|
|
/// Offset a pointer to project to a field of a struct/union. Unlike `place_field`, this is
|
|
|
|
/// always possible without allocating, so it can take `&self`. Also return the field's layout.
|
|
|
|
/// This supports both struct and array fields.
|
|
|
|
///
|
|
|
|
/// This also works for arrays, but then the `usize` index type is restricting.
|
|
|
|
/// For indexing into arrays, use `mplace_index`.
|
|
|
|
pub fn mplace_field(
|
|
|
|
&self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &MPlaceTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
field: usize,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
let offset = base.layout.fields.offset(field);
|
|
|
|
let field_layout = base.layout.field(self, field);
|
|
|
|
|
|
|
|
// Offset may need adjustment for unsized fields.
|
|
|
|
let (meta, offset) = if field_layout.is_unsized() {
|
|
|
|
// Re-use parent metadata to determine dynamic field layout.
|
|
|
|
// With custom DSTS, this *will* execute user-defined code, but the same
|
|
|
|
// happens at run-time so that's okay.
|
|
|
|
match self.size_and_align_of(&base.meta, &field_layout)? {
|
|
|
|
Some((_, align)) => (base.meta, offset.align_to(align)),
|
|
|
|
None => {
|
|
|
|
// For unsized types with an extern type tail we perform no adjustments.
|
|
|
|
// NOTE: keep this in sync with `PlaceRef::project_field` in the codegen backend.
|
|
|
|
assert!(matches!(base.meta, MemPlaceMeta::None));
|
|
|
|
(base.meta, offset)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// base.meta could be present; we might be accessing a sized field of an unsized
|
|
|
|
// struct.
|
|
|
|
(MemPlaceMeta::None, offset)
|
|
|
|
};
|
|
|
|
|
|
|
|
// We do not look at `base.layout.align` nor `field_layout.align`, unlike
|
|
|
|
// codegen -- mostly to see if we can get away with that
|
2022-07-14 19:32:45 -05:00
|
|
|
base.offset_with_meta(offset, meta, field_layout, self)
|
2022-07-04 07:48:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the place of a field inside the place, and also the field's type.
|
|
|
|
/// Just a convenience function, but used quite a bit.
|
|
|
|
/// This is the only projection that might have a side-effect: We cannot project
|
|
|
|
/// into the field of a local `ScalarPair`, we have to first allocate it.
|
|
|
|
pub fn place_field(
|
|
|
|
&mut self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &PlaceTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
field: usize,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
// FIXME: We could try to be smarter and avoid allocation for fields that span the
|
|
|
|
// entire place.
|
|
|
|
let base = self.force_allocation(base)?;
|
|
|
|
Ok(self.mplace_field(&base, field)?.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn operand_field(
|
|
|
|
&self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &OpTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
field: usize,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
2022-11-18 03:18:32 -06:00
|
|
|
let base = match base.as_mplace_or_imm() {
|
|
|
|
Left(ref mplace) => {
|
2022-07-04 07:48:05 -05:00
|
|
|
// We can reuse the mplace field computation logic for indirect operands.
|
|
|
|
let field = self.mplace_field(mplace, field)?;
|
|
|
|
return Ok(field.into());
|
|
|
|
}
|
2022-11-18 03:18:32 -06:00
|
|
|
Right(value) => value,
|
2022-07-04 07:48:05 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
let field_layout = base.layout.field(self, field);
|
|
|
|
let offset = base.layout.fields.offset(field);
|
|
|
|
// This makes several assumptions about what layouts we will encounter; we match what
|
|
|
|
// codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`).
|
|
|
|
let field_val: Immediate<_> = match (*base, base.layout.abi) {
|
2022-08-07 09:36:42 -05:00
|
|
|
// if the entire value is uninit, then so is the field (can happen in ConstProp)
|
|
|
|
(Immediate::Uninit, _) => Immediate::Uninit,
|
2022-07-04 07:48:05 -05:00
|
|
|
// the field contains no information, can be left uninit
|
|
|
|
_ if field_layout.is_zst() => Immediate::Uninit,
|
|
|
|
// the field covers the entire type
|
|
|
|
_ if field_layout.size == base.layout.size => {
|
|
|
|
assert!(match (base.layout.abi, field_layout.abi) {
|
|
|
|
(Abi::Scalar(..), Abi::Scalar(..)) => true,
|
|
|
|
(Abi::ScalarPair(..), Abi::ScalarPair(..)) => true,
|
|
|
|
_ => false,
|
|
|
|
});
|
|
|
|
assert!(offset.bytes() == 0);
|
|
|
|
*base
|
|
|
|
}
|
|
|
|
// extract fields from types with `ScalarPair` ABI
|
|
|
|
(Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => {
|
|
|
|
assert!(matches!(field_layout.abi, Abi::Scalar(..)));
|
|
|
|
Immediate::from(if offset.bytes() == 0 {
|
|
|
|
debug_assert_eq!(field_layout.size, a.size(self));
|
|
|
|
a_val
|
|
|
|
} else {
|
|
|
|
debug_assert_eq!(offset, a.size(self).align_to(b.align(self).abi));
|
|
|
|
debug_assert_eq!(field_layout.size, b.size(self));
|
|
|
|
b_val
|
|
|
|
})
|
|
|
|
}
|
2022-08-07 09:36:42 -05:00
|
|
|
// everything else is a bug
|
2022-07-04 07:48:05 -05:00
|
|
|
_ => span_bug!(
|
|
|
|
self.cur_span(),
|
|
|
|
"invalid field access on immediate {}, layout {:#?}",
|
|
|
|
base,
|
|
|
|
base.layout
|
|
|
|
),
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(ImmTy::from_immediate(field_val, field_layout).into())
|
|
|
|
}
|
|
|
|
|
|
|
|
//# Downcasting
|
|
|
|
|
|
|
|
pub fn mplace_downcast(
|
|
|
|
&self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &MPlaceTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
variant: VariantIdx,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
// Downcasts only change the layout.
|
|
|
|
// (In particular, no check about whether this is even the active variant -- that's by design,
|
|
|
|
// see https://github.com/rust-lang/rust/issues/93688#issuecomment-1032929496.)
|
|
|
|
assert!(!base.meta.has_meta());
|
|
|
|
let mut base = *base;
|
|
|
|
base.layout = base.layout.for_variant(self, variant);
|
|
|
|
Ok(base)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn place_downcast(
|
|
|
|
&self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &PlaceTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
variant: VariantIdx,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
// Downcast just changes the layout
|
2022-07-15 21:58:20 -05:00
|
|
|
let mut base = base.clone();
|
2022-07-04 07:48:05 -05:00
|
|
|
base.layout = base.layout.for_variant(self, variant);
|
|
|
|
Ok(base)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn operand_downcast(
|
|
|
|
&self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &OpTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
variant: VariantIdx,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
// Downcast just changes the layout
|
2022-07-15 21:58:20 -05:00
|
|
|
let mut base = base.clone();
|
2022-07-04 07:48:05 -05:00
|
|
|
base.layout = base.layout.for_variant(self, variant);
|
|
|
|
Ok(base)
|
|
|
|
}
|
|
|
|
|
|
|
|
//# Slice indexing
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn operand_index(
|
|
|
|
&self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &OpTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
index: u64,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
// Not using the layout method because we want to compute on u64
|
|
|
|
match base.layout.fields {
|
|
|
|
abi::FieldsShape::Array { stride, count: _ } => {
|
|
|
|
// `count` is nonsense for slices, use the dynamic length instead.
|
|
|
|
let len = base.len(self)?;
|
|
|
|
if index >= len {
|
|
|
|
// This can only be reached in ConstProp and non-rustc-MIR.
|
|
|
|
throw_ub!(BoundsCheckFailed { len, index });
|
|
|
|
}
|
|
|
|
let offset = stride * index; // `Size` multiplication
|
|
|
|
// All fields have the same layout.
|
|
|
|
let field_layout = base.layout.field(self, 0);
|
2022-07-14 19:32:45 -05:00
|
|
|
base.offset(offset, field_layout, self)
|
2022-07-04 07:48:05 -05:00
|
|
|
}
|
|
|
|
_ => span_bug!(
|
|
|
|
self.cur_span(),
|
|
|
|
"`mplace_index` called on non-array type {:?}",
|
|
|
|
base.layout.ty
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-27 05:15:06 -06:00
|
|
|
/// Iterates over all fields of an array. Much more efficient than doing the
|
|
|
|
/// same by repeatedly calling `operand_index`.
|
2022-07-04 07:48:05 -05:00
|
|
|
pub fn operand_array_fields<'a>(
|
|
|
|
&self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &'a OpTy<'tcx, Prov>,
|
|
|
|
) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, OpTy<'tcx, Prov>>> + 'a> {
|
2022-07-04 07:48:05 -05:00
|
|
|
let len = base.len(self)?; // also asserts that we have a type where this makes sense
|
|
|
|
let abi::FieldsShape::Array { stride, .. } = base.layout.fields else {
|
|
|
|
span_bug!(self.cur_span(), "operand_array_fields: expected an array layout");
|
|
|
|
};
|
2022-07-14 19:32:45 -05:00
|
|
|
let field_layout = base.layout.field(self, 0);
|
2022-07-04 07:48:05 -05:00
|
|
|
let dl = &self.tcx.data_layout;
|
|
|
|
// `Size` multiplication
|
2022-07-14 19:32:45 -05:00
|
|
|
Ok((0..len).map(move |i| base.offset(stride * i, field_layout, dl)))
|
2022-07-04 07:48:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Index into an array.
|
|
|
|
pub fn mplace_index(
|
|
|
|
&self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &MPlaceTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
index: u64,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
Ok(self.operand_index(&base.into(), index)?.assert_mem_place())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn place_index(
|
|
|
|
&mut self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &PlaceTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
index: u64,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
// There's not a lot we can do here, since we cannot have a place to a part of a local. If
|
|
|
|
// we are accessing the only element of a 1-element array, it's still the entire local...
|
|
|
|
// that doesn't seem worth it.
|
|
|
|
let base = self.force_allocation(base)?;
|
|
|
|
Ok(self.mplace_index(&base, index)?.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
//# ConstantIndex support
|
|
|
|
|
|
|
|
fn operand_constant_index(
|
|
|
|
&self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &OpTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
offset: u64,
|
|
|
|
min_length: u64,
|
|
|
|
from_end: bool,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
let n = base.len(self)?;
|
|
|
|
if n < min_length {
|
|
|
|
// This can only be reached in ConstProp and non-rustc-MIR.
|
|
|
|
throw_ub!(BoundsCheckFailed { len: min_length, index: n });
|
|
|
|
}
|
|
|
|
|
|
|
|
let index = if from_end {
|
|
|
|
assert!(0 < offset && offset <= min_length);
|
|
|
|
n.checked_sub(offset).unwrap()
|
|
|
|
} else {
|
|
|
|
assert!(offset < min_length);
|
|
|
|
offset
|
|
|
|
};
|
|
|
|
|
|
|
|
self.operand_index(base, index)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn place_constant_index(
|
|
|
|
&mut self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &PlaceTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
offset: u64,
|
|
|
|
min_length: u64,
|
|
|
|
from_end: bool,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
let base = self.force_allocation(base)?;
|
|
|
|
Ok(self
|
|
|
|
.operand_constant_index(&base.into(), offset, min_length, from_end)?
|
|
|
|
.assert_mem_place()
|
|
|
|
.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
//# Subslicing
|
|
|
|
|
|
|
|
fn operand_subslice(
|
|
|
|
&self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &OpTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
from: u64,
|
|
|
|
to: u64,
|
|
|
|
from_end: bool,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
let len = base.len(self)?; // also asserts that we have a type where this makes sense
|
|
|
|
let actual_to = if from_end {
|
|
|
|
if from.checked_add(to).map_or(true, |to| to > len) {
|
|
|
|
// This can only be reached in ConstProp and non-rustc-MIR.
|
|
|
|
throw_ub!(BoundsCheckFailed { len: len, index: from.saturating_add(to) });
|
|
|
|
}
|
|
|
|
len.checked_sub(to).unwrap()
|
|
|
|
} else {
|
|
|
|
to
|
|
|
|
};
|
|
|
|
|
|
|
|
// Not using layout method because that works with usize, and does not work with slices
|
|
|
|
// (that have count 0 in their layout).
|
|
|
|
let from_offset = match base.layout.fields {
|
|
|
|
abi::FieldsShape::Array { stride, .. } => stride * from, // `Size` multiplication is checked
|
|
|
|
_ => {
|
|
|
|
span_bug!(self.cur_span(), "unexpected layout of index access: {:#?}", base.layout)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Compute meta and new layout
|
|
|
|
let inner_len = actual_to.checked_sub(from).unwrap();
|
|
|
|
let (meta, ty) = match base.layout.ty.kind() {
|
|
|
|
// It is not nice to match on the type, but that seems to be the only way to
|
|
|
|
// implement this.
|
|
|
|
ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(*inner, inner_len)),
|
|
|
|
ty::Slice(..) => {
|
2023-02-14 08:31:26 -06:00
|
|
|
let len = Scalar::from_target_usize(inner_len, self);
|
2022-07-04 07:48:05 -05:00
|
|
|
(MemPlaceMeta::Meta(len), base.layout.ty)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
span_bug!(self.cur_span(), "cannot subslice non-array type: `{:?}`", base.layout.ty)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let layout = self.layout_of(ty)?;
|
2022-07-14 19:32:45 -05:00
|
|
|
base.offset_with_meta(from_offset, meta, layout, self)
|
2022-07-04 07:48:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn place_subslice(
|
|
|
|
&mut self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &PlaceTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
from: u64,
|
|
|
|
to: u64,
|
|
|
|
from_end: bool,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
let base = self.force_allocation(base)?;
|
|
|
|
Ok(self.operand_subslice(&base.into(), from, to, from_end)?.assert_mem_place().into())
|
|
|
|
}
|
|
|
|
|
|
|
|
//# Applying a general projection
|
|
|
|
|
|
|
|
/// Projects into a place.
|
|
|
|
#[instrument(skip(self), level = "trace")]
|
|
|
|
pub fn place_projection(
|
|
|
|
&mut self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &PlaceTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
proj_elem: mir::PlaceElem<'tcx>,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
use rustc_middle::mir::ProjectionElem::*;
|
|
|
|
Ok(match proj_elem {
|
2022-07-27 06:58:34 -05:00
|
|
|
OpaqueCast(ty) => {
|
|
|
|
let mut place = base.clone();
|
|
|
|
place.layout = self.layout_of(ty)?;
|
|
|
|
place
|
|
|
|
}
|
2022-07-04 07:48:05 -05:00
|
|
|
Field(field, _) => self.place_field(base, field.index())?,
|
|
|
|
Downcast(_, variant) => self.place_downcast(base, variant)?,
|
|
|
|
Deref => self.deref_operand(&self.place_to_op(base)?)?.into(),
|
|
|
|
Index(local) => {
|
|
|
|
let layout = self.layout_of(self.tcx.types.usize)?;
|
|
|
|
let n = self.local_to_op(self.frame(), local, Some(layout))?;
|
2023-02-14 08:31:26 -06:00
|
|
|
let n = self.read_target_usize(&n)?;
|
2022-07-04 07:48:05 -05:00
|
|
|
self.place_index(base, n)?
|
|
|
|
}
|
|
|
|
ConstantIndex { offset, min_length, from_end } => {
|
|
|
|
self.place_constant_index(base, offset, min_length, from_end)?
|
|
|
|
}
|
|
|
|
Subslice { from, to, from_end } => self.place_subslice(base, from, to, from_end)?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[instrument(skip(self), level = "trace")]
|
|
|
|
pub fn operand_projection(
|
|
|
|
&self,
|
2022-07-18 17:47:31 -05:00
|
|
|
base: &OpTy<'tcx, M::Provenance>,
|
2022-07-04 07:48:05 -05:00
|
|
|
proj_elem: mir::PlaceElem<'tcx>,
|
2022-07-18 17:47:31 -05:00
|
|
|
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
2022-07-04 07:48:05 -05:00
|
|
|
use rustc_middle::mir::ProjectionElem::*;
|
|
|
|
Ok(match proj_elem {
|
2022-07-27 06:58:34 -05:00
|
|
|
OpaqueCast(ty) => {
|
|
|
|
let mut op = base.clone();
|
|
|
|
op.layout = self.layout_of(ty)?;
|
|
|
|
op
|
|
|
|
}
|
2022-07-04 07:48:05 -05:00
|
|
|
Field(field, _) => self.operand_field(base, field.index())?,
|
|
|
|
Downcast(_, variant) => self.operand_downcast(base, variant)?,
|
|
|
|
Deref => self.deref_operand(base)?.into(),
|
|
|
|
Index(local) => {
|
|
|
|
let layout = self.layout_of(self.tcx.types.usize)?;
|
|
|
|
let n = self.local_to_op(self.frame(), local, Some(layout))?;
|
2023-02-14 08:31:26 -06:00
|
|
|
let n = self.read_target_usize(&n)?;
|
2022-07-04 07:48:05 -05:00
|
|
|
self.operand_index(base, n)?
|
|
|
|
}
|
|
|
|
ConstantIndex { offset, min_length, from_end } => {
|
|
|
|
self.operand_constant_index(base, offset, min_length, from_end)?
|
|
|
|
}
|
|
|
|
Subslice { from, to, from_end } => self.operand_subslice(base, from, to, from_end)?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|