1
Fork 0

interpret: make write functions generic over the place type

This commit is contained in:
Ralf Jung 2023-07-25 22:04:02 +02:00
parent 4fc6b33474
commit 00fb45dccd
26 changed files with 243 additions and 213 deletions

View file

@ -345,7 +345,7 @@ fn valtree_into_mplace<'tcx>(
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
let scalar_int = valtree.unwrap_leaf();
debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place);
ecx.write_immediate(Immediate::Scalar(scalar_int.into()), &place.into()).unwrap();
ecx.write_immediate(Immediate::Scalar(scalar_int.into()), place).unwrap();
}
ty::Ref(_, inner_ty, _) => {
let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
@ -369,7 +369,7 @@ fn valtree_into_mplace<'tcx>(
};
debug!(?imm);
ecx.write_immediate(imm, &place.into()).unwrap();
ecx.write_immediate(imm, place).unwrap();
}
ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => {
let branches = valtree.unwrap_branch();
@ -452,11 +452,11 @@ fn valtree_into_mplace<'tcx>(
if let Some(variant_idx) = variant_idx {
// don't forget filling the place with the discriminant of the enum
ecx.write_discriminant(variant_idx, &place.into()).unwrap();
ecx.write_discriminant(variant_idx, place).unwrap();
}
debug!("dump of place after writing discriminant:");
dump_place(ecx, place.into());
dump_place(ecx, place.clone().into());
}
_ => bug!("shouldn't have created a ValTree for {:?}", ty),
}

View file

@ -5,7 +5,8 @@ use rustc_middle::{mir, ty};
use rustc_target::abi::{self, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants};
use super::{ImmTy, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Scalar};
use super::place::Writeable;
use super::{ImmTy, InterpCx, InterpResult, Machine, OpTy, Scalar};
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Writes the discriminant of the given variant.
@ -13,7 +14,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
pub fn write_discriminant(
&mut self,
variant_index: VariantIdx,
dest: &PlaceTy<'tcx, M::Provenance>,
dest: &impl Writeable<'tcx, M::Provenance>,
) -> InterpResult<'tcx> {
// Layout computation excludes uninhabited variants from consideration
// therefore there's no way to represent those variants in the given layout.
@ -21,11 +22,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// discriminant, so we cannot do anything here.
// When evaluating we will always error before even getting here, but ConstProp 'executes'
// dead code, so we cannot ICE here.
if dest.layout.for_variant(self, variant_index).abi.is_uninhabited() {
if dest.layout().for_variant(self, variant_index).abi.is_uninhabited() {
throw_ub!(UninhabitedEnumVariantWritten(variant_index))
}
match dest.layout.variants {
match dest.layout().variants {
abi::Variants::Single { index } => {
assert_eq!(index, variant_index);
}
@ -38,8 +39,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// No need to validate that the discriminant here because the
// `TyAndLayout::for_variant()` call earlier already checks the variant is valid.
let discr_val =
dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val;
let discr_val = dest
.layout()
.ty
.discriminant_for_variant(*self.tcx, variant_index)
.unwrap()
.val;
// raw discriminants for enums are isize or bigger during
// their computation, but the in-memory tag is the smallest possible

View file

@ -432,7 +432,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} else {
self.project_index(&input, i)?.into()
};
self.copy_op(&value, &place.into(), /*allow_transmute*/ false)?;
self.copy_op(&value, &place, /*allow_transmute*/ false)?;
}
}
sym::simd_extract => {

View file

@ -101,11 +101,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
// Initialize fields.
self.write_immediate(file.to_ref(self), &self.project_field(&location, 0).unwrap().into())
self.write_immediate(file.to_ref(self), &self.project_field(&location, 0).unwrap())
.expect("writing to memory we just allocated cannot fail");
self.write_scalar(line, &self.project_field(&location, 1).unwrap().into())
self.write_scalar(line, &self.project_field(&location, 1).unwrap())
.expect("writing to memory we just allocated cannot fail");
self.write_scalar(col, &self.project_field(&location, 2).unwrap().into())
self.write_scalar(col, &self.project_field(&location, 2).unwrap())
.expect("writing to memory we just allocated cannot fail");
location

View file

@ -25,7 +25,7 @@ pub use self::intern::{intern_const_alloc_recursive, InternKind};
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
pub use self::operand::{ImmTy, Immediate, OpTy, Operand};
pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy, Writeable};
pub use self::projection::Projectable;
pub use self::terminator::FnArg;
pub use self::validity::{CtfeValidationMode, RefTracking};

View file

@ -312,13 +312,13 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
}
}
impl<'mir, 'tcx: 'mir, Prov: Provenance> Projectable<'mir, 'tcx, Prov> for ImmTy<'tcx, Prov> {
impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> {
#[inline(always)]
fn layout(&self) -> TyAndLayout<'tcx> {
self.layout
}
fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
_ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
@ -337,7 +337,7 @@ impl<'mir, 'tcx: 'mir, Prov: Provenance> Projectable<'mir, 'tcx, Prov> for ImmTy
Ok(self.offset_(offset, layout, cx))
}
fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
_ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
@ -362,15 +362,13 @@ impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> {
}
}
impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
for OpTy<'tcx, Prov>
{
impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> {
#[inline(always)]
fn layout(&self) -> TyAndLayout<'tcx> {
self.layout
}
fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
_ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
@ -394,7 +392,7 @@ impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
}
}
fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
_ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {

View file

@ -92,6 +92,14 @@ pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
pub align: Align,
}
impl<'tcx, Prov: Provenance> std::ops::Deref for MPlaceTy<'tcx, Prov> {
type Target = MemPlace<Prov>;
#[inline(always)]
fn deref(&self) -> &MemPlace<Prov> {
&self.mplace
}
}
#[derive(Copy, Clone, Debug)]
pub enum Place<Prov: Provenance = AllocId> {
/// A place referring to a value allocated in the `Memory` system.
@ -125,14 +133,6 @@ impl<'tcx, Prov: Provenance> std::ops::Deref for PlaceTy<'tcx, Prov> {
}
}
impl<'tcx, Prov: Provenance> std::ops::Deref for MPlaceTy<'tcx, Prov> {
type Target = MemPlace<Prov>;
#[inline(always)]
fn deref(&self) -> &MemPlace<Prov> {
&self.mplace
}
}
impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> {
#[inline(always)]
fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self {
@ -140,20 +140,6 @@ impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov>
}
}
impl<'tcx, Prov: Provenance> From<&'_ MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> {
#[inline(always)]
fn from(mplace: &MPlaceTy<'tcx, Prov>) -> Self {
PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align }
}
}
impl<'tcx, Prov: Provenance> From<&'_ mut MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> {
#[inline(always)]
fn from(mplace: &mut MPlaceTy<'tcx, Prov>) -> Self {
PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align }
}
}
impl<Prov: Provenance> MemPlace<Prov> {
#[inline(always)]
pub fn from_ptr(ptr: Pointer<Option<Prov>>) -> Self {
@ -229,15 +215,13 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> {
}
}
impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
for MPlaceTy<'tcx, Prov>
{
impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
#[inline(always)]
fn layout(&self) -> TyAndLayout<'tcx> {
self.layout
}
fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
_ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
@ -258,7 +242,7 @@ impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
})
}
fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
_ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
@ -266,6 +250,54 @@ impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
}
}
impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> {
#[inline(always)]
fn layout(&self) -> TyAndLayout<'tcx> {
self.layout
}
fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
ecx.place_meta(self)
}
fn offset_with_meta(
&self,
offset: Size,
meta: MemPlaceMeta<Prov>,
layout: TyAndLayout<'tcx>,
cx: &impl HasDataLayout,
) -> InterpResult<'tcx, Self> {
Ok(match self.as_mplace_or_local() {
Left(mplace) => mplace.offset_with_meta(offset, meta, layout, cx)?.into(),
Right((frame, local, old_offset)) => {
assert_matches!(meta, MemPlaceMeta::None); // we couldn't store it anyway...
let new_offset = cx
.data_layout()
.offset(old_offset.unwrap_or(Size::ZERO).bytes(), offset.bytes())?;
PlaceTy {
place: Place::Local {
frame,
local,
offset: Some(Size::from_bytes(new_offset)),
},
align: self.align.restrict_for_offset(offset),
layout,
}
}
})
}
fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
ecx.place_to_op(self)
}
}
// These are defined here because they produce a place.
impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> {
#[inline(always)]
@ -314,53 +346,51 @@ impl<'tcx, Prov: Provenance + 'static> PlaceTy<'tcx, Prov> {
}
}
impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
for PlaceTy<'tcx, Prov>
{
pub trait Writeable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> {
fn as_mplace_or_local(
&self,
) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, Align, TyAndLayout<'tcx>)>;
fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
ecx: &mut InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>>;
}
impl<'tcx, Prov: Provenance + 'static> Writeable<'tcx, Prov> for PlaceTy<'tcx, Prov> {
#[inline(always)]
fn layout(&self) -> TyAndLayout<'tcx> {
self.layout
fn as_mplace_or_local(
&self,
) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, Align, TyAndLayout<'tcx>)>
{
self.as_mplace_or_local()
.map_right(|(frame, local, offset)| (frame, local, offset, self.align, self.layout))
}
fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
#[inline(always)]
fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
ecx.place_meta(self)
ecx: &mut InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> {
ecx.force_allocation(self)
}
}
impl<'tcx, Prov: Provenance + 'static> Writeable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
#[inline(always)]
fn as_mplace_or_local(
&self,
) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, Align, TyAndLayout<'tcx>)>
{
Left(self.clone())
}
fn offset_with_meta(
#[inline(always)]
fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
offset: Size,
meta: MemPlaceMeta<Prov>,
layout: TyAndLayout<'tcx>,
cx: &impl HasDataLayout,
) -> InterpResult<'tcx, Self> {
Ok(match self.as_mplace_or_local() {
Left(mplace) => mplace.offset_with_meta(offset, meta, layout, cx)?.into(),
Right((frame, local, old_offset)) => {
assert_matches!(meta, MemPlaceMeta::None); // we couldn't store it anyway...
let new_offset = cx
.data_layout()
.offset(old_offset.unwrap_or(Size::ZERO).bytes(), offset.bytes())?;
PlaceTy {
place: Place::Local {
frame,
local,
offset: Some(Size::from_bytes(new_offset)),
},
align: self.align.restrict_for_offset(offset),
layout,
}
}
})
}
fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
ecx.place_to_op(self)
_ecx: &mut InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> {
Ok(self.clone())
}
}
@ -537,13 +567,13 @@ where
pub fn write_immediate(
&mut self,
src: Immediate<M::Provenance>,
dest: &PlaceTy<'tcx, M::Provenance>,
dest: &impl Writeable<'tcx, M::Provenance>,
) -> InterpResult<'tcx> {
self.write_immediate_no_validate(src, dest)?;
if M::enforce_validity(self, dest.layout) {
if M::enforce_validity(self, dest.layout()) {
// Data got changed, better make sure it matches the type!
self.validate_operand(&self.place_to_op(dest)?)?;
self.validate_operand(&dest.to_op(self)?)?;
}
Ok(())
@ -554,7 +584,7 @@ where
pub fn write_scalar(
&mut self,
val: impl Into<Scalar<M::Provenance>>,
dest: &PlaceTy<'tcx, M::Provenance>,
dest: &impl Writeable<'tcx, M::Provenance>,
) -> InterpResult<'tcx> {
self.write_immediate(Immediate::Scalar(val.into()), dest)
}
@ -564,7 +594,7 @@ where
pub fn write_pointer(
&mut self,
ptr: impl Into<Pointer<Option<M::Provenance>>>,
dest: &PlaceTy<'tcx, M::Provenance>,
dest: &impl Writeable<'tcx, M::Provenance>,
) -> InterpResult<'tcx> {
self.write_scalar(Scalar::from_maybe_pointer(ptr.into(), self), dest)
}
@ -575,20 +605,19 @@ where
fn write_immediate_no_validate(
&mut self,
src: Immediate<M::Provenance>,
dest: &PlaceTy<'tcx, M::Provenance>,
dest: &impl Writeable<'tcx, M::Provenance>,
) -> InterpResult<'tcx> {
assert!(dest.layout.is_sized(), "Cannot write unsized immediate data");
trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
assert!(dest.layout().is_sized(), "Cannot write unsized immediate data");
// See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`,
// but not factored as a separate function.
let mplace = match dest.place {
Place::Local { frame, local, offset } => {
let mplace = match dest.as_mplace_or_local() {
Right((frame, local, offset, align, layout)) => {
if offset.is_some() {
// This has been projected to a part of this local. We could have complicated
// logic to still keep this local as an `Operand`... but it's much easier to
// just fall back to the indirect path.
*self.force_allocation(dest)?
dest.force_mplace(self)?
} else {
match M::access_local_mut(self, frame, local)? {
Operand::Immediate(local_val) => {
@ -623,16 +652,16 @@ where
}
Operand::Indirect(mplace) => {
// The local is in memory, go on below.
*mplace
MPlaceTy { mplace: *mplace, align, layout }
}
}
}
}
Place::Ptr(mplace) => mplace, // already referring to memory
Left(mplace) => mplace, // already referring to memory
};
// This is already in memory, write there.
self.write_immediate_to_mplace_no_validate(src, dest.layout, dest.align, mplace)
self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.align, mplace.mplace)
}
/// Write an immediate to memory.
@ -696,16 +725,19 @@ where
}
}
pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
pub fn write_uninit(
&mut self,
dest: &impl Writeable<'tcx, M::Provenance>,
) -> InterpResult<'tcx> {
let mplace = match dest.as_mplace_or_local() {
Left(mplace) => mplace,
Right((frame, local, offset)) => {
Right((frame, local, offset, align, layout)) => {
if offset.is_some() {
// This has been projected to a part of this local. We could have complicated
// logic to still keep this local as an `Operand`... but it's much easier to
// just fall back to the indirect path.
// FIXME: share the logic with `write_immediate_no_validate`.
self.force_allocation(dest)?
dest.force_mplace(self)?
} else {
match M::access_local_mut(self, frame, local)? {
Operand::Immediate(local) => {
@ -714,7 +746,7 @@ where
}
Operand::Indirect(mplace) => {
// The local is in memory, go on below.
MPlaceTy { mplace: *mplace, layout: dest.layout, align: dest.align }
MPlaceTy { mplace: *mplace, layout, align }
}
}
}
@ -735,14 +767,14 @@ where
pub fn copy_op(
&mut self,
src: &OpTy<'tcx, M::Provenance>,
dest: &PlaceTy<'tcx, M::Provenance>,
dest: &impl Writeable<'tcx, M::Provenance>,
allow_transmute: bool,
) -> InterpResult<'tcx> {
self.copy_op_no_validate(src, dest, allow_transmute)?;
if M::enforce_validity(self, dest.layout) {
if M::enforce_validity(self, dest.layout()) {
// Data got changed, better make sure it matches the type!
self.validate_operand(&self.place_to_op(dest)?)?;
self.validate_operand(&dest.to_op(self)?)?;
}
Ok(())
@ -756,19 +788,19 @@ where
fn copy_op_no_validate(
&mut self,
src: &OpTy<'tcx, M::Provenance>,
dest: &PlaceTy<'tcx, M::Provenance>,
dest: &impl Writeable<'tcx, M::Provenance>,
allow_transmute: bool,
) -> InterpResult<'tcx> {
// We do NOT compare the types for equality, because well-typed code can
// actually "transmute" `&mut T` to `&T` in an assignment without a cast.
let layout_compat =
mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout);
mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout());
if !allow_transmute && !layout_compat {
span_bug!(
self.cur_span(),
"type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
src.layout.ty,
dest.layout.ty,
dest.layout().ty,
);
}
@ -784,10 +816,10 @@ where
if src.layout.is_unsized() {
throw_inval!(SizeOfUnsizedType(src.layout.ty));
}
if dest.layout.is_unsized() {
throw_inval!(SizeOfUnsizedType(dest.layout.ty));
if dest.layout().is_unsized() {
throw_inval!(SizeOfUnsizedType(dest.layout().ty));
}
assert_eq!(src.layout.size, dest.layout.size);
assert_eq!(src.layout.size, dest.layout().size);
// Yay, we got a value that we can write directly.
return if layout_compat {
self.write_immediate_no_validate(*src_val, dest)
@ -796,7 +828,7 @@ where
// loaded using the offsets defined by `src.layout`. When we put this back into
// the destination, we have to use the same offsets! So (a) we make sure we
// write back to memory, and (b) we use `dest` *with the source layout*.
let dest_mem = self.force_allocation(dest)?;
let dest_mem = dest.force_mplace(self)?;
self.write_immediate_to_mplace_no_validate(
*src_val,
src.layout,
@ -808,9 +840,9 @@ where
Left(mplace) => mplace,
};
// Slow path, this does not fit into an immediate. Just memcpy.
trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout().ty);
let dest = self.force_allocation(&dest)?;
let dest = dest.force_mplace(self)?;
let Some((dest_size, _)) = self.size_and_align_of_mplace(&dest)? else {
span_bug!(self.cur_span(), "copy_op needs (dynamically) sized values")
};
@ -928,7 +960,7 @@ where
operands: &IndexSlice<FieldIdx, mir::Operand<'tcx>>,
dest: &PlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx> {
self.write_uninit(&dest)?;
self.write_uninit(dest)?;
let (variant_index, variant_dest, active_field_index) = match *kind {
mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => {
let variant_dest = self.project_downcast(dest, variant_index)?;
@ -945,7 +977,7 @@ where
let op = self.eval_operand(operand, Some(field_dest.layout))?;
self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?;
}
self.write_discriminant(variant_index, &dest)
self.write_discriminant(variant_index, dest)
}
pub fn raw_const_to_mplace(
@ -983,7 +1015,7 @@ where
/// Turn a `dyn* Trait` type into an value with the actual dynamic type.
/// Also returns the vtable.
pub(super) fn unpack_dyn_star<P: Projectable<'mir, 'tcx, M::Provenance>>(
pub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>(
&self,
val: &P,
) -> InterpResult<'tcx, (P, Pointer<Option<M::Provenance>>)> {

View file

@ -16,21 +16,20 @@ use rustc_target::abi::HasDataLayout;
use rustc_target::abi::Size;
use rustc_target::abi::{self, VariantIdx};
use super::MPlaceTy;
use super::{InterpCx, InterpResult, Machine, MemPlaceMeta, OpTy, Provenance, Scalar};
use super::{InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar};
/// A thing that we can project into, and that has a layout.
pub trait Projectable<'mir, 'tcx: 'mir, Prov: Provenance>: Sized {
pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug {
/// Get the layout.
fn layout(&self) -> TyAndLayout<'tcx>;
/// Get the metadata of a wide value.
fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>>;
fn len<M: Machine<'mir, 'tcx, Provenance = Prov>>(
fn len<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, u64> {
@ -67,7 +66,7 @@ pub trait Projectable<'mir, 'tcx: 'mir, Prov: Provenance>: Sized {
/// Convert this to an `OpTy`. This might be an irreversible transformation, but is useful for
/// reading from this thing.
fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self,
ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>;
@ -85,7 +84,7 @@ where
///
/// This also works for arrays, but then the `usize` index type is restricting.
/// For indexing into arrays, use `mplace_index`.
pub fn project_field<P: Projectable<'mir, 'tcx, M::Provenance>>(
pub fn project_field<P: Projectable<'tcx, M::Provenance>>(
&self,
base: &P,
field: usize,
@ -128,7 +127,7 @@ where
}
/// Downcasting to an enum variant.
pub fn project_downcast<P: Projectable<'mir, 'tcx, M::Provenance>>(
pub fn project_downcast<P: Projectable<'tcx, M::Provenance>>(
&self,
base: &P,
variant: VariantIdx,
@ -149,7 +148,7 @@ where
}
/// Compute the offset and field layout for accessing the given index.
pub fn project_index<P: Projectable<'mir, 'tcx, M::Provenance>>(
pub fn project_index<P: Projectable<'tcx, M::Provenance>>(
&self,
base: &P,
index: u64,
@ -178,7 +177,7 @@ where
base.offset(offset, field_layout, self)
}
fn project_constant_index<P: Projectable<'mir, 'tcx, M::Provenance>>(
fn project_constant_index<P: Projectable<'tcx, M::Provenance>>(
&self,
base: &P,
offset: u64,
@ -204,7 +203,7 @@ where
/// Iterates over all fields of an array. Much more efficient than doing the
/// same by repeatedly calling `operand_index`.
pub fn project_array_fields<'a, P: Projectable<'mir, 'tcx, M::Provenance>>(
pub fn project_array_fields<'a, P: Projectable<'tcx, M::Provenance>>(
&self,
base: &'a P,
) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, P>> + 'a>
@ -224,7 +223,7 @@ where
}
/// Subslicing
fn project_subslice<P: Projectable<'mir, 'tcx, M::Provenance>>(
fn project_subslice<P: Projectable<'tcx, M::Provenance>>(
&self,
base: &P,
from: u64,
@ -284,9 +283,7 @@ where
#[instrument(skip(self), level = "trace")]
pub fn project<P>(&self, base: &P, proj_elem: mir::PlaceElem<'tcx>) -> InterpResult<'tcx, P>
where
P: Projectable<'mir, 'tcx, M::Provenance>
+ From<MPlaceTy<'tcx, M::Provenance>>
+ std::fmt::Debug,
P: Projectable<'tcx, M::Provenance> + From<MPlaceTy<'tcx, M::Provenance>> + std::fmt::Debug,
{
use rustc_middle::mir::ProjectionElem::*;
Ok(match proj_elem {

View file

@ -198,7 +198,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} else {
// Write the src to the first element.
let first = self.project_index(&dest, 0)?;
self.copy_op(&src, &first.into(), /*allow_transmute*/ false)?;
self.copy_op(&src, &first, /*allow_transmute*/ false)?;
// This is performance-sensitive code for big static/const arrays! So we
// avoid writing each operand individually and instead just make many copies

View file

@ -13,9 +13,7 @@ use super::{InterpCx, MPlaceTy, Machine, Projectable};
/// How to traverse a value and what to do when we are at the leaves.
pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
type V: Projectable<'mir, 'tcx, M::Provenance>
+ From<MPlaceTy<'tcx, M::Provenance>>
+ std::fmt::Debug;
type V: Projectable<'tcx, M::Provenance> + From<MPlaceTy<'tcx, M::Provenance>>;
/// The visitor must have an `InterpCx` in it.
fn ecx(&self) -> &InterpCx<'mir, 'tcx, M>;