1
Fork 0

interpret: track place alignment together with the type, not the value

This commit is contained in:
Ralf Jung 2022-07-03 10:21:47 -04:00
parent ada8c80bed
commit 8955686e05
3 changed files with 117 additions and 95 deletions

View file

@ -808,7 +808,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.stack_mut().pop().expect("tried to pop a stack frame, but there were none"); self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
if !unwinding { if !unwinding {
let op = self.access_local(&frame, mir::RETURN_PLACE, None)?; let op = self.local_to_op(&frame, mir::RETURN_PLACE, None)?;
self.copy_op_transmute(&op, &frame.return_place)?; self.copy_op_transmute(&op, &frame.return_place)?;
trace!("{:?}", self.dump_place(*frame.return_place)); trace!("{:?}", self.dump_place(*frame.return_place));
} }
@ -981,8 +981,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug
LocalValue::Live(Operand::Indirect(mplace)) => { LocalValue::Live(Operand::Indirect(mplace)) => {
write!( write!(
fmt, fmt,
" by align({}){} ref {:?}:", " by {} ref {:?}:",
mplace.align.bytes(),
match mplace.meta { match mplace.meta {
MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta), MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta),
MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(), MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(),
@ -1011,13 +1010,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug
write!(fmt, ": {:?}", self.ecx.dump_allocs(allocs.into_iter().flatten().collect())) write!(fmt, ": {:?}", self.ecx.dump_allocs(allocs.into_iter().flatten().collect()))
} }
Place::Ptr(mplace) => match mplace.ptr.provenance.and_then(Provenance::get_alloc_id) { Place::Ptr(mplace) => match mplace.ptr.provenance.and_then(Provenance::get_alloc_id) {
Some(alloc_id) => write!( Some(alloc_id) => {
fmt, write!(fmt, "by ref {:?}: {:?}", mplace.ptr, self.ecx.dump_alloc(alloc_id))
"by align({}) ref {:?}: {:?}", }
mplace.align.bytes(),
mplace.ptr,
self.ecx.dump_alloc(alloc_id)
),
ptr => write!(fmt, " integral by ref: {:?}", ptr), ptr => write!(fmt, " integral by ref: {:?}", ptr),
}, },
} }

View file

@ -10,7 +10,7 @@ use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
use rustc_middle::ty::{ConstInt, DelaySpanBugEmitted, Ty}; use rustc_middle::ty::{ConstInt, DelaySpanBugEmitted, Ty};
use rustc_middle::{mir, ty}; use rustc_middle::{mir, ty};
use rustc_target::abi::{self, Abi, HasDataLayout, Size, TagEncoding}; use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants}; use rustc_target::abi::{VariantIdx, Variants};
use super::{ use super::{
@ -177,10 +177,17 @@ pub enum Operand<Tag: Provenance = AllocId> {
pub struct OpTy<'tcx, Tag: Provenance = AllocId> { pub struct OpTy<'tcx, Tag: Provenance = AllocId> {
op: Operand<Tag>, // Keep this private; it helps enforce invariants. op: Operand<Tag>, // Keep this private; it helps enforce invariants.
pub layout: TyAndLayout<'tcx>, pub layout: TyAndLayout<'tcx>,
/// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct:
/// it needs to have a different alignment than the field type would usually have.
/// So we represent this here with a separate field that "overwrites" `layout.align`.
/// This means `layout.align` should never be used for an `OpTy`!
/// `None` means "alignment does not matter since this is a by-value operand"
/// (`Operand::Immediate`).
pub align: Option<Align>,
} }
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(OpTy<'_>, 80); rustc_data_structures::static_assert_size!(OpTy<'_>, 88);
impl<'tcx, Tag: Provenance> std::ops::Deref for OpTy<'tcx, Tag> { impl<'tcx, Tag: Provenance> std::ops::Deref for OpTy<'tcx, Tag> {
type Target = Operand<Tag>; type Target = Operand<Tag>;
@ -193,28 +200,28 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for OpTy<'tcx, Tag> {
impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> { impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
#[inline(always)] #[inline(always)]
fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self { fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
OpTy { op: Operand::Indirect(*mplace), layout: mplace.layout } OpTy { op: Operand::Indirect(*mplace), layout: mplace.layout, align: Some(mplace.align) }
} }
} }
impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> { impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
#[inline(always)] #[inline(always)]
fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self { fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self {
OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout } OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) }
} }
} }
impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> { impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
#[inline(always)] #[inline(always)]
fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self { fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self {
OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout } OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) }
} }
} }
impl<'tcx, Tag: Provenance> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> { impl<'tcx, Tag: Provenance> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
#[inline(always)] #[inline(always)]
fn from(val: ImmTy<'tcx, Tag>) -> Self { fn from(val: ImmTy<'tcx, Tag>) -> Self {
OpTy { op: Operand::Immediate(val.imm), layout: val.layout } OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None }
} }
} }
@ -450,7 +457,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
), ),
}; };
Ok(OpTy { op: Operand::Immediate(field_val), layout: field_layout }) Ok(OpTy { op: Operand::Immediate(field_val), layout: field_layout, align: None })
} }
pub fn operand_index( pub fn operand_index(
@ -522,7 +529,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// ///
/// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an
/// OpTy from a local /// OpTy from a local
pub fn access_local( pub fn local_to_op(
&self, &self,
frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
local: mir::Local, local: mir::Local,
@ -535,7 +542,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} else { } else {
M::access_local(&self, frame, local)? M::access_local(&self, frame, local)?
}; };
Ok(OpTy { op, layout }) Ok(OpTy { op, layout, align: Some(layout.align.abi) })
} }
/// Every place can be read from, so we can turn them into an operand. /// Every place can be read from, so we can turn them into an operand.
@ -549,10 +556,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let op = match **place { let op = match **place {
Place::Ptr(mplace) => Operand::Indirect(mplace), Place::Ptr(mplace) => Operand::Indirect(mplace),
Place::Local { frame, local } => { Place::Local { frame, local } => {
*self.access_local(&self.stack()[frame], local, None)? *self.local_to_op(&self.stack()[frame], local, None)?
} }
}; };
Ok(OpTy { op, layout: place.layout }) Ok(OpTy { op, layout: place.layout, align: Some(place.align) })
} }
/// Evaluate a place with the goal of reading from it. This lets us sometimes /// Evaluate a place with the goal of reading from it. This lets us sometimes
@ -566,7 +573,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// here is not the entire place. // here is not the entire place.
let layout = if place.projection.is_empty() { layout } else { None }; let layout = if place.projection.is_empty() { layout } else { None };
let base_op = self.access_local(self.frame(), place.local, layout)?; let base_op = self.local_to_op(self.frame(), place.local, layout)?;
let op = place let op = place
.projection .projection
@ -603,11 +610,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Constant(ref constant) => { Constant(ref constant) => {
let val = let val =
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?; self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?;
// This can still fail: // This can still fail:
// * During ConstProp, with `TooGeneric` or since the `required_consts` were not all // * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
// checked yet. // checked yet.
// * During CTFE, since promoteds in `const`/`static` initializer bodies can fail. // * During CTFE, since promoteds in `const`/`static` initializer bodies can fail.
self.mir_const_to_op(&val, layout)? self.mir_const_to_op(&val, layout)?
} }
}; };
@ -683,7 +690,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// We rely on mutability being set correctly in that allocation to prevent writes // We rely on mutability being set correctly in that allocation to prevent writes
// where none should happen. // where none should happen.
let ptr = self.global_base_pointer(Pointer::new(id, offset))?; let ptr = self.global_base_pointer(Pointer::new(id, offset))?;
Operand::Indirect(MemPlace::from_ptr(ptr.into(), layout.align.abi)) Operand::Indirect(MemPlace::from_ptr(ptr.into()))
} }
ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()), ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()),
ConstValue::Slice { data, start, end } => { ConstValue::Slice { data, start, end } => {
@ -700,7 +707,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
)) ))
} }
}; };
Ok(OpTy { op, layout }) Ok(OpTy { op, layout, align: Some(layout.align.abi) })
} }
/// Read discriminant, return the runtime value as well as the variant index. /// Read discriminant, return the runtime value as well as the variant index.

View file

@ -57,7 +57,6 @@ impl<Tag: Provenance> MemPlaceMeta<Tag> {
pub struct MemPlace<Tag: Provenance = AllocId> { pub struct MemPlace<Tag: Provenance = AllocId> {
/// The pointer can be a pure integer, with the `None` tag. /// The pointer can be a pure integer, with the `None` tag.
pub ptr: Pointer<Option<Tag>>, pub ptr: Pointer<Option<Tag>>,
pub align: Align,
/// Metadata for unsized places. Interpretation is up to the type. /// Metadata for unsized places. Interpretation is up to the type.
/// Must not be present for sized types, but can be missing for unsized types /// Must not be present for sized types, but can be missing for unsized types
/// (e.g., `extern type`). /// (e.g., `extern type`).
@ -65,7 +64,7 @@ pub struct MemPlace<Tag: Provenance = AllocId> {
} }
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(MemPlace, 48); rustc_data_structures::static_assert_size!(MemPlace, 40);
#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)] #[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)]
pub enum Place<Tag: Provenance = AllocId> { pub enum Place<Tag: Provenance = AllocId> {
@ -78,12 +77,17 @@ pub enum Place<Tag: Provenance = AllocId> {
} }
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(Place, 56); rustc_data_structures::static_assert_size!(Place, 48);
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct PlaceTy<'tcx, Tag: Provenance = AllocId> { pub struct PlaceTy<'tcx, Tag: Provenance = AllocId> {
place: Place<Tag>, // Keep this private; it helps enforce invariants. place: Place<Tag>, // Keep this private; it helps enforce invariants.
pub layout: TyAndLayout<'tcx>, pub layout: TyAndLayout<'tcx>,
/// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct:
/// it needs to have a different alignment than the field type would usually have.
/// So we represent this here with a separate field that "overwrites" `layout.align`.
/// This means `layout.align` should never be used for a `PlaceTy`!
pub align: Align,
} }
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
@ -102,6 +106,11 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for PlaceTy<'tcx, Tag> {
pub struct MPlaceTy<'tcx, Tag: Provenance = AllocId> { pub struct MPlaceTy<'tcx, Tag: Provenance = AllocId> {
mplace: MemPlace<Tag>, mplace: MemPlace<Tag>,
pub layout: TyAndLayout<'tcx>, pub layout: TyAndLayout<'tcx>,
/// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct:
/// it needs to have a different alignment than the field type would usually have.
/// So we represent this here with a separate field that "overwrites" `layout.align`.
/// This means `layout.align` should never be used for a `MPlaceTy`!
pub align: Align,
} }
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
@ -118,28 +127,28 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for MPlaceTy<'tcx, Tag> {
impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> { impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
#[inline(always)] #[inline(always)]
fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self { fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
PlaceTy { place: Place::Ptr(*mplace), layout: mplace.layout } PlaceTy { place: Place::Ptr(*mplace), layout: mplace.layout, align: mplace.align }
} }
} }
impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> { impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
#[inline(always)] #[inline(always)]
fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self { fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self {
PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout } PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align }
} }
} }
impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> { impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
#[inline(always)] #[inline(always)]
fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self { fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self {
PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout } PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align }
} }
} }
impl<Tag: Provenance> MemPlace<Tag> { impl<Tag: Provenance> MemPlace<Tag> {
#[inline(always)] #[inline(always)]
pub fn from_ptr(ptr: Pointer<Option<Tag>>, align: Align) -> Self { pub fn from_ptr(ptr: Pointer<Option<Tag>>) -> Self {
MemPlace { ptr, align, meta: MemPlaceMeta::None } MemPlace { ptr, meta: MemPlaceMeta::None }
} }
/// Adjust the provenance of the main pointer (metadata is unaffected). /// Adjust the provenance of the main pointer (metadata is unaffected).
@ -170,11 +179,7 @@ impl<Tag: Provenance> MemPlace<Tag> {
meta: MemPlaceMeta<Tag>, meta: MemPlaceMeta<Tag>,
cx: &impl HasDataLayout, cx: &impl HasDataLayout,
) -> InterpResult<'tcx, Self> { ) -> InterpResult<'tcx, Self> {
Ok(MemPlace { Ok(MemPlace { ptr: self.ptr.offset(offset, cx)?, meta })
ptr: self.ptr.offset(offset, cx)?,
align: self.align.restrict_for_offset(offset),
meta,
})
} }
} }
@ -185,7 +190,7 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
let align = layout.align.abi; let align = layout.align.abi;
let ptr = Pointer::new(None, Size::from_bytes(align.bytes())); // no provenance, absolute address let ptr = Pointer::new(None, Size::from_bytes(align.bytes())); // no provenance, absolute address
// `Poison` this to make sure that the pointer value `ptr` is never observable by the program. // `Poison` this to make sure that the pointer value `ptr` is never observable by the program.
MPlaceTy { mplace: MemPlace { ptr, align, meta: MemPlaceMeta::Poison }, layout } MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::Poison }, layout, align }
} }
#[inline] #[inline]
@ -196,12 +201,16 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
layout: TyAndLayout<'tcx>, layout: TyAndLayout<'tcx>,
cx: &impl HasDataLayout, cx: &impl HasDataLayout,
) -> InterpResult<'tcx, Self> { ) -> InterpResult<'tcx, Self> {
Ok(MPlaceTy { mplace: self.mplace.offset(offset, meta, cx)?, layout }) Ok(MPlaceTy {
mplace: self.mplace.offset(offset, meta, cx)?,
align: self.align.restrict_for_offset(offset),
layout,
})
} }
#[inline] #[inline]
pub fn from_aligned_ptr(ptr: Pointer<Option<Tag>>, layout: TyAndLayout<'tcx>) -> Self { pub fn from_aligned_ptr(ptr: Pointer<Option<Tag>>, layout: TyAndLayout<'tcx>) -> Self {
MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout } MPlaceTy { mplace: MemPlace::from_ptr(ptr), layout, align: layout.align.abi }
} }
#[inline] #[inline]
@ -210,10 +219,10 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
layout: TyAndLayout<'tcx>, layout: TyAndLayout<'tcx>,
meta: MemPlaceMeta<Tag>, meta: MemPlaceMeta<Tag>,
) -> Self { ) -> Self {
let mut mplace = MemPlace::from_ptr(ptr, layout.align.abi); let mut mplace = MemPlace::from_ptr(ptr);
mplace.meta = meta; mplace.meta = meta;
MPlaceTy { mplace, layout } MPlaceTy { mplace, layout, align: layout.align.abi }
} }
#[inline] #[inline]
@ -250,7 +259,9 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> {
/// read from the resulting mplace, not to get its address back. /// read from the resulting mplace, not to get its address back.
pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> { pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
match **self { match **self {
Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }), Operand::Indirect(mplace) => {
Ok(MPlaceTy { mplace, layout: self.layout, align: self.align.unwrap() })
}
Operand::Immediate(_) if self.layout.is_zst() => Ok(MPlaceTy::dangling(self.layout)), Operand::Immediate(_) if self.layout.is_zst() => Ok(MPlaceTy::dangling(self.layout)),
Operand::Immediate(imm) => Err(ImmTy::from_immediate(imm, self.layout)), Operand::Immediate(imm) => Err(ImmTy::from_immediate(imm, self.layout)),
} }
@ -264,20 +275,19 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> {
} }
} }
impl<Tag: Provenance> Place<Tag> {
#[inline]
pub fn assert_mem_place(self) -> MemPlace<Tag> {
match self {
Place::Ptr(mplace) => mplace,
_ => bug!("assert_mem_place: expected Place::Ptr, got {:?}", self),
}
}
}
impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> { impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> {
/// A place is either an mplace or some local.
#[inline]
pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Tag>, (usize, mir::Local)> {
match **self {
Place::Ptr(mplace) => Ok(MPlaceTy { mplace, layout: self.layout, align: self.align }),
Place::Local { frame, local } => Err((frame, local)),
}
}
#[inline] #[inline]
pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> { pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> {
MPlaceTy { mplace: self.place.assert_mem_place(), layout: self.layout } self.try_as_mplace().unwrap()
} }
} }
@ -306,16 +316,10 @@ where
Immediate::ScalarPair(ptr, meta) => (ptr, MemPlaceMeta::Meta(meta.check_init()?)), Immediate::ScalarPair(ptr, meta) => (ptr, MemPlaceMeta::Meta(meta.check_init()?)),
}; };
let mplace = MemPlace { let mplace = MemPlace { ptr: self.scalar_to_ptr(ptr.check_init()?)?, meta };
ptr: self.scalar_to_ptr(ptr.check_init()?)?, // When deref'ing a pointer, the *static* alignment given by the type is what matters.
// We could use the run-time alignment here. For now, we do not, because let align = layout.align.abi;
// the point of tracking the alignment here is to make sure that the *static* Ok(MPlaceTy { mplace, layout, align })
// alignment information emitted with the loads is correct. The run-time
// alignment can only be more restrictive.
align: layout.align.abi,
meta,
};
Ok(MPlaceTy { mplace, layout })
} }
/// Take an operand, representing a pointer, and dereference it to a place -- that /// Take an operand, representing a pointer, and dereference it to a place -- that
@ -368,7 +372,7 @@ where
let (size, align) = self let (size, align) = self
.size_and_align_of_mplace(&mplace)? .size_and_align_of_mplace(&mplace)?
.unwrap_or((mplace.layout.size, mplace.layout.align.abi)); .unwrap_or((mplace.layout.size, mplace.layout.align.abi));
assert!(mplace.mplace.align <= align, "dynamic alignment less strict than static one?"); assert!(mplace.align <= align, "dynamic alignment less strict than static one?");
let align = M::enforce_alignment(self).then_some(align); let align = M::enforce_alignment(self).then_some(align);
self.check_ptr_access_align(mplace.ptr, size, align.unwrap_or(Align::ONE), msg)?; self.check_ptr_access_align(mplace.ptr, size, align.unwrap_or(Align::ONE), msg)?;
Ok(()) Ok(())
@ -533,7 +537,7 @@ where
Index(local) => { Index(local) => {
let layout = self.layout_of(self.tcx.types.usize)?; let layout = self.layout_of(self.tcx.types.usize)?;
let n = self.access_local(self.frame(), local, Some(layout))?; let n = self.local_to_op(self.frame(), local, Some(layout))?;
let n = self.read_scalar(&n)?; let n = self.read_scalar(&n)?;
let n = n.to_machine_usize(self)?; let n = n.to_machine_usize(self)?;
self.mplace_index(base, n)? self.mplace_index(base, n)?
@ -608,11 +612,9 @@ where
variant: VariantIdx, variant: VariantIdx,
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
// Downcast just changes the layout // Downcast just changes the layout
Ok(match base.place { Ok(match base.try_as_mplace() {
Place::Ptr(mplace) => { Ok(mplace) => self.mplace_downcast(&mplace, variant)?.into(),
self.mplace_downcast(&MPlaceTy { mplace, layout: base.layout }, variant)?.into() Err(..) => {
}
Place::Local { .. } => {
let layout = base.layout.for_variant(self, variant); let layout = base.layout.for_variant(self, variant);
PlaceTy { layout, ..*base } PlaceTy { layout, ..*base }
} }
@ -649,6 +651,16 @@ where
self.mplace_to_simd(&mplace) self.mplace_to_simd(&mplace)
} }
pub fn local_to_place(
&self,
frame: usize,
local: mir::Local,
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
let layout = self.layout_of_local(&self.stack()[frame], local, None)?;
let place = Place::Local { frame, local };
Ok(PlaceTy { place, layout, align: layout.align.abi })
}
/// Computes a place. You should only use this if you intend to write into this /// Computes a place. You should only use this if you intend to write into this
/// place; for reading, a more efficient alternative is `eval_place_to_op`. /// place; for reading, a more efficient alternative is `eval_place_to_op`.
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
@ -656,11 +668,7 @@ where
&mut self, &mut self,
place: mir::Place<'tcx>, place: mir::Place<'tcx>,
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
let mut place_ty = PlaceTy { let mut place_ty = self.local_to_place(self.frame_idx(), place.local)?;
// This works even for dead/uninitialized locals; we check further when writing
place: Place::Local { frame: self.frame_idx(), local: place.local },
layout: self.layout_of_local(self.frame(), place.local, None)?,
};
for elem in place.projection.iter() { for elem in place.projection.iter() {
place_ty = self.place_projection(&place_ty, &elem)? place_ty = self.place_projection(&place_ty, &elem)?
@ -668,14 +676,19 @@ where
trace!("{:?}", self.dump_place(place_ty.place)); trace!("{:?}", self.dump_place(place_ty.place));
// Sanity-check the type we ended up with. // Sanity-check the type we ended up with.
debug_assert!(mir_assign_valid_types( debug_assert!(
mir_assign_valid_types(
*self.tcx, *self.tcx,
self.param_env, self.param_env,
self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
place.ty(&self.frame().body.local_decls, *self.tcx).ty place.ty(&self.frame().body.local_decls, *self.tcx).ty
)?)?, )?)?,
place_ty.layout, place_ty.layout,
)); ),
"eval_place of a MIR place with type {:?} produced an interpret place with type {:?}",
place.ty(&self.frame().body.local_decls, *self.tcx).ty,
place_ty.layout.ty,
);
Ok(place_ty) Ok(place_ty)
} }
@ -746,7 +759,7 @@ where
} }
Place::Ptr(mplace) => mplace, // already referring to memory Place::Ptr(mplace) => mplace, // already referring to memory
}; };
let dest = MPlaceTy { mplace, layout: dest.layout }; let dest = MPlaceTy { mplace, layout: dest.layout, align: dest.align };
// This is already in memory, write there. // This is already in memory, write there.
self.write_immediate_to_mplace_no_validate(src, &dest) self.write_immediate_to_mplace_no_validate(src, &dest)
@ -808,9 +821,9 @@ where
} }
pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
let mplace = match dest.place { let mplace = match dest.try_as_mplace() {
Place::Ptr(mplace) => MPlaceTy { mplace, layout: dest.layout }, Ok(mplace) => mplace,
Place::Local { frame, local } => { Err((frame, local)) => {
match M::access_local_mut(self, frame, local)? { match M::access_local_mut(self, frame, local)? {
Ok(local) => match dest.layout.abi { Ok(local) => match dest.layout.abi {
Abi::Scalar(_) => { Abi::Scalar(_) => {
@ -830,7 +843,7 @@ where
}, },
Err(mplace) => { Err(mplace) => {
// The local is in memory, go on below. // The local is in memory, go on below.
MPlaceTy { mplace, layout: dest.layout } MPlaceTy { mplace, layout: dest.layout, align: dest.align }
} }
} }
} }
@ -948,7 +961,7 @@ where
let dest = self.force_allocation(dest)?; let dest = self.force_allocation(dest)?;
self.copy_op_no_validate( self.copy_op_no_validate(
src, src,
&PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }), &PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout, align: dest.align }),
)?; )?;
if M::enforce_validity(self) { if M::enforce_validity(self) {
@ -989,12 +1002,16 @@ where
.size_and_align_of(&meta, &local_layout)? .size_and_align_of(&meta, &local_layout)?
.expect("Cannot allocate for non-dyn-sized type"); .expect("Cannot allocate for non-dyn-sized type");
let ptr = self.allocate_ptr(size, align, MemoryKind::Stack)?; let ptr = self.allocate_ptr(size, align, MemoryKind::Stack)?;
let mplace = MemPlace { ptr: ptr.into(), align, meta }; let mplace = MemPlace { ptr: ptr.into(), meta };
if let LocalValue::Live(Operand::Immediate(value)) = local_val { if let LocalValue::Live(Operand::Immediate(value)) = local_val {
// Preserve old value. // Preserve old value.
// We don't have to validate as we can assume the local // We don't have to validate as we can assume the local
// was already valid for its type. // was already valid for its type.
let mplace = MPlaceTy { mplace, layout: local_layout }; let mplace = MPlaceTy {
mplace,
layout: local_layout,
align: local_layout.align.abi,
};
self.write_immediate_to_mplace_no_validate(value, &mplace)?; self.write_immediate_to_mplace_no_validate(value, &mplace)?;
} }
// Now we can call `access_mut` again, asserting it goes well, // Now we can call `access_mut` again, asserting it goes well,
@ -1009,7 +1026,7 @@ where
Place::Ptr(mplace) => (mplace, None), Place::Ptr(mplace) => (mplace, None),
}; };
// Return with the original layout, so that the caller can go on // Return with the original layout, so that the caller can go on
Ok((MPlaceTy { mplace, layout: place.layout }, size)) Ok((MPlaceTy { mplace, layout: place.layout, align: place.align }, size))
} }
#[inline(always)] #[inline(always)]
@ -1038,15 +1055,14 @@ where
) -> MPlaceTy<'tcx, M::PointerTag> { ) -> MPlaceTy<'tcx, M::PointerTag> {
let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl); let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl);
let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self); let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self);
let mplace = let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) };
MemPlace { ptr: ptr.into(), align: Align::ONE, meta: MemPlaceMeta::Meta(meta) };
let ty = self.tcx.mk_ref( let ty = self.tcx.mk_ref(
self.tcx.lifetimes.re_static, self.tcx.lifetimes.re_static,
ty::TypeAndMut { ty: self.tcx.types.str_, mutbl }, ty::TypeAndMut { ty: self.tcx.types.str_, mutbl },
); );
let layout = self.layout_of(ty).unwrap(); let layout = self.layout_of(ty).unwrap();
MPlaceTy { mplace, layout } MPlaceTy { mplace, layout, align: layout.align.abi }
} }
/// Writes the discriminant of the given variant. /// Writes the discriminant of the given variant.
@ -1166,7 +1182,11 @@ where
assert_eq!(align, layout.align.abi); assert_eq!(align, layout.align.abi);
} }
let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, layout }; let mplace = MPlaceTy {
mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace },
layout,
align: layout.align.abi,
};
Ok((instance, mplace)) Ok((instance, mplace))
} }
} }