Auto merge of #98846 - RalfJung:alignment-is-a-type-thing, r=oli-obk
interpret: track place alignment together with the type, not the value This matches how I handle alignment in [MiniRust](https://github.com/RalfJung/minirust). I think it makes conceptually a lot more sense. Fixes https://github.com/rust-lang/rust/issues/63085 r? `@oli-obk`
This commit is contained in:
commit
4008dd8c6d
@ -808,7 +808,7 @@ pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
|
||||
self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
|
||||
|
||||
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)?;
|
||||
trace!("{:?}", self.dump_place(*frame.return_place));
|
||||
}
|
||||
@ -981,8 +981,7 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
LocalValue::Live(Operand::Indirect(mplace)) => {
|
||||
write!(
|
||||
fmt,
|
||||
" by align({}){} ref {:?}:",
|
||||
mplace.align.bytes(),
|
||||
" by {} ref {:?}:",
|
||||
match mplace.meta {
|
||||
MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta),
|
||||
MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(),
|
||||
@ -1011,13 +1010,9 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(fmt, ": {:?}", self.ecx.dump_allocs(allocs.into_iter().flatten().collect()))
|
||||
}
|
||||
Place::Ptr(mplace) => match mplace.ptr.provenance.and_then(Provenance::get_alloc_id) {
|
||||
Some(alloc_id) => write!(
|
||||
fmt,
|
||||
"by align({}) ref {:?}: {:?}",
|
||||
mplace.align.bytes(),
|
||||
mplace.ptr,
|
||||
self.ecx.dump_alloc(alloc_id)
|
||||
),
|
||||
Some(alloc_id) => {
|
||||
write!(fmt, "by ref {:?}: {:?}", mplace.ptr, self.ecx.dump_alloc(alloc_id))
|
||||
}
|
||||
ptr => write!(fmt, " integral by ref: {:?}", ptr),
|
||||
},
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
|
||||
use rustc_middle::ty::{ConstInt, DelaySpanBugEmitted, 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 super::{
|
||||
@ -177,10 +177,18 @@ pub enum Operand<Tag: Provenance = AllocId> {
|
||||
pub struct OpTy<'tcx, Tag: Provenance = AllocId> {
|
||||
op: Operand<Tag>, // Keep this private; it helps enforce invariants.
|
||||
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`); this field is only relevant for `Operand::Indirect`.
|
||||
/// Also CTFE ignores alignment anyway, so this is for Miri only.
|
||||
pub align: Option<Align>,
|
||||
}
|
||||
|
||||
#[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> {
|
||||
type Target = Operand<Tag>;
|
||||
@ -193,28 +201,28 @@ fn deref(&self) -> &Operand<Tag> {
|
||||
impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
|
||||
#[inline(always)]
|
||||
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> {
|
||||
#[inline(always)]
|
||||
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> {
|
||||
#[inline(always)]
|
||||
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> {
|
||||
#[inline(always)]
|
||||
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 +458,7 @@ pub fn operand_field(
|
||||
),
|
||||
};
|
||||
|
||||
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(
|
||||
@ -522,7 +530,7 @@ pub fn operand_to_simd(
|
||||
///
|
||||
/// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an
|
||||
/// OpTy from a local
|
||||
pub fn access_local(
|
||||
pub fn local_to_op(
|
||||
&self,
|
||||
frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
|
||||
local: mir::Local,
|
||||
@ -535,7 +543,7 @@ pub fn access_local(
|
||||
} else {
|
||||
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.
|
||||
@ -549,10 +557,10 @@ pub fn place_to_op(
|
||||
let op = match **place {
|
||||
Place::Ptr(mplace) => Operand::Indirect(mplace),
|
||||
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
|
||||
@ -566,7 +574,7 @@ pub fn eval_place_to_op(
|
||||
// here is not the entire place.
|
||||
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
|
||||
.projection
|
||||
@ -603,11 +611,11 @@ pub fn eval_operand(
|
||||
Constant(ref constant) => {
|
||||
let val =
|
||||
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?;
|
||||
|
||||
// This can still fail:
|
||||
// * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
|
||||
// checked yet.
|
||||
// * During CTFE, since promoteds in `const`/`static` initializer bodies can fail.
|
||||
|
||||
self.mir_const_to_op(&val, layout)?
|
||||
}
|
||||
};
|
||||
@ -683,7 +691,7 @@ pub(crate) fn const_val_to_op(
|
||||
// We rely on mutability being set correctly in that allocation to prevent writes
|
||||
// where none should happen.
|
||||
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::Slice { data, start, end } => {
|
||||
@ -700,7 +708,7 @@ pub(crate) fn const_val_to_op(
|
||||
))
|
||||
}
|
||||
};
|
||||
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.
|
||||
|
@ -57,7 +57,6 @@ fn has_meta(self) -> bool {
|
||||
pub struct MemPlace<Tag: Provenance = AllocId> {
|
||||
/// The pointer can be a pure integer, with the `None` tag.
|
||||
pub ptr: Pointer<Option<Tag>>,
|
||||
pub align: Align,
|
||||
/// Metadata for unsized places. Interpretation is up to the type.
|
||||
/// Must not be present for sized types, but can be missing for unsized types
|
||||
/// (e.g., `extern type`).
|
||||
@ -65,7 +64,7 @@ pub struct MemPlace<Tag: Provenance = AllocId> {
|
||||
}
|
||||
|
||||
#[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)]
|
||||
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"))]
|
||||
rustc_data_structures::static_assert_size!(Place, 56);
|
||||
rustc_data_structures::static_assert_size!(Place, 48);
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PlaceTy<'tcx, Tag: Provenance = AllocId> {
|
||||
place: Place<Tag>, // Keep this private; it helps enforce invariants.
|
||||
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"))]
|
||||
@ -102,6 +106,11 @@ fn deref(&self) -> &Place<Tag> {
|
||||
pub struct MPlaceTy<'tcx, Tag: Provenance = AllocId> {
|
||||
mplace: MemPlace<Tag>,
|
||||
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"))]
|
||||
@ -118,28 +127,28 @@ fn deref(&self) -> &MemPlace<Tag> {
|
||||
impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
|
||||
#[inline(always)]
|
||||
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> {
|
||||
#[inline(always)]
|
||||
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> {
|
||||
#[inline(always)]
|
||||
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> {
|
||||
#[inline(always)]
|
||||
pub fn from_ptr(ptr: Pointer<Option<Tag>>, align: Align) -> Self {
|
||||
MemPlace { ptr, align, meta: MemPlaceMeta::None }
|
||||
pub fn from_ptr(ptr: Pointer<Option<Tag>>) -> Self {
|
||||
MemPlace { ptr, meta: MemPlaceMeta::None }
|
||||
}
|
||||
|
||||
/// Adjust the provenance of the main pointer (metadata is unaffected).
|
||||
@ -170,11 +179,7 @@ pub fn offset<'tcx>(
|
||||
meta: MemPlaceMeta<Tag>,
|
||||
cx: &impl HasDataLayout,
|
||||
) -> InterpResult<'tcx, Self> {
|
||||
Ok(MemPlace {
|
||||
ptr: self.ptr.offset(offset, cx)?,
|
||||
align: self.align.restrict_for_offset(offset),
|
||||
meta,
|
||||
})
|
||||
Ok(MemPlace { ptr: self.ptr.offset(offset, cx)?, meta })
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,7 +190,7 @@ pub fn dangling(layout: TyAndLayout<'tcx>) -> Self {
|
||||
let align = layout.align.abi;
|
||||
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.
|
||||
MPlaceTy { mplace: MemPlace { ptr, align, meta: MemPlaceMeta::Poison }, layout }
|
||||
MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::Poison }, layout, align }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -196,12 +201,16 @@ pub fn offset(
|
||||
layout: TyAndLayout<'tcx>,
|
||||
cx: &impl HasDataLayout,
|
||||
) -> 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]
|
||||
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]
|
||||
@ -210,10 +219,10 @@ pub fn from_aligned_ptr_with_meta(
|
||||
layout: TyAndLayout<'tcx>,
|
||||
meta: MemPlaceMeta<Tag>,
|
||||
) -> Self {
|
||||
let mut mplace = MemPlace::from_ptr(ptr, layout.align.abi);
|
||||
let mut mplace = MemPlace::from_ptr(ptr);
|
||||
mplace.meta = meta;
|
||||
|
||||
MPlaceTy { mplace, layout }
|
||||
MPlaceTy { mplace, layout, align: layout.align.abi }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -250,7 +259,9 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> {
|
||||
/// read from the resulting mplace, not to get its address back.
|
||||
pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
|
||||
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(imm) => Err(ImmTy::from_immediate(imm, self.layout)),
|
||||
}
|
||||
@ -264,20 +275,19 @@ pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Tag> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag: Provenance> Place<Tag> {
|
||||
impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> {
|
||||
/// A place is either an mplace or some local.
|
||||
#[inline]
|
||||
pub fn assert_mem_place(self) -> MemPlace<Tag> {
|
||||
match self {
|
||||
Place::Ptr(mplace) => mplace,
|
||||
_ => bug!("assert_mem_place: expected Place::Ptr, got {:?}", self),
|
||||
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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> {
|
||||
#[inline]
|
||||
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 @@ pub fn ref_to_mplace(
|
||||
Immediate::ScalarPair(ptr, meta) => (ptr, MemPlaceMeta::Meta(meta.check_init()?)),
|
||||
};
|
||||
|
||||
let mplace = MemPlace {
|
||||
ptr: self.scalar_to_ptr(ptr.check_init()?)?,
|
||||
// We could use the run-time alignment here. For now, we do not, because
|
||||
// the point of tracking the alignment here is to make sure that the *static*
|
||||
// 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 })
|
||||
let mplace = MemPlace { ptr: self.scalar_to_ptr(ptr.check_init()?)?, meta };
|
||||
// When deref'ing a pointer, the *static* alignment given by the type is what matters.
|
||||
let align = layout.align.abi;
|
||||
Ok(MPlaceTy { mplace, layout, align })
|
||||
}
|
||||
|
||||
/// Take an operand, representing a pointer, and dereference it to a place -- that
|
||||
@ -368,7 +372,7 @@ fn check_mplace_access(
|
||||
let (size, align) = self
|
||||
.size_and_align_of_mplace(&mplace)?
|
||||
.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);
|
||||
self.check_ptr_access_align(mplace.ptr, size, align.unwrap_or(Align::ONE), msg)?;
|
||||
Ok(())
|
||||
@ -533,7 +537,7 @@ pub(super) fn mplace_projection(
|
||||
|
||||
Index(local) => {
|
||||
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 = n.to_machine_usize(self)?;
|
||||
self.mplace_index(base, n)?
|
||||
@ -608,11 +612,9 @@ pub fn place_downcast(
|
||||
variant: VariantIdx,
|
||||
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
|
||||
// Downcast just changes the layout
|
||||
Ok(match base.place {
|
||||
Place::Ptr(mplace) => {
|
||||
self.mplace_downcast(&MPlaceTy { mplace, layout: base.layout }, variant)?.into()
|
||||
}
|
||||
Place::Local { .. } => {
|
||||
Ok(match base.try_as_mplace() {
|
||||
Ok(mplace) => self.mplace_downcast(&mplace, variant)?.into(),
|
||||
Err(..) => {
|
||||
let layout = base.layout.for_variant(self, variant);
|
||||
PlaceTy { layout, ..*base }
|
||||
}
|
||||
@ -649,6 +651,16 @@ pub fn place_to_simd(
|
||||
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
|
||||
/// place; for reading, a more efficient alternative is `eval_place_to_op`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
@ -656,11 +668,7 @@ pub fn eval_place(
|
||||
&mut self,
|
||||
place: mir::Place<'tcx>,
|
||||
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
|
||||
let mut place_ty = PlaceTy {
|
||||
// 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)?,
|
||||
};
|
||||
let mut place_ty = self.local_to_place(self.frame_idx(), place.local)?;
|
||||
|
||||
for elem in place.projection.iter() {
|
||||
place_ty = self.place_projection(&place_ty, &elem)?
|
||||
@ -668,14 +676,19 @@ pub fn eval_place(
|
||||
|
||||
trace!("{:?}", self.dump_place(place_ty.place));
|
||||
// Sanity-check the type we ended up with.
|
||||
debug_assert!(mir_assign_valid_types(
|
||||
*self.tcx,
|
||||
self.param_env,
|
||||
self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
|
||||
place.ty(&self.frame().body.local_decls, *self.tcx).ty
|
||||
)?)?,
|
||||
place_ty.layout,
|
||||
));
|
||||
debug_assert!(
|
||||
mir_assign_valid_types(
|
||||
*self.tcx,
|
||||
self.param_env,
|
||||
self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
|
||||
place.ty(&self.frame().body.local_decls, *self.tcx).ty
|
||||
)?)?,
|
||||
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)
|
||||
}
|
||||
|
||||
@ -746,7 +759,7 @@ fn write_immediate_no_validate(
|
||||
}
|
||||
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.
|
||||
self.write_immediate_to_mplace_no_validate(src, &dest)
|
||||
@ -808,9 +821,9 @@ fn write_immediate_to_mplace_no_validate(
|
||||
}
|
||||
|
||||
pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
|
||||
let mplace = match dest.place {
|
||||
Place::Ptr(mplace) => MPlaceTy { mplace, layout: dest.layout },
|
||||
Place::Local { frame, local } => {
|
||||
let mplace = match dest.try_as_mplace() {
|
||||
Ok(mplace) => mplace,
|
||||
Err((frame, local)) => {
|
||||
match M::access_local_mut(self, frame, local)? {
|
||||
Ok(local) => match dest.layout.abi {
|
||||
Abi::Scalar(_) => {
|
||||
@ -830,7 +843,7 @@ pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpRes
|
||||
},
|
||||
Err(mplace) => {
|
||||
// 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 @@ pub fn copy_op_transmute(
|
||||
let dest = self.force_allocation(dest)?;
|
||||
self.copy_op_no_validate(
|
||||
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) {
|
||||
@ -989,12 +1002,16 @@ pub fn force_allocation_maybe_sized(
|
||||
.size_and_align_of(&meta, &local_layout)?
|
||||
.expect("Cannot allocate for non-dyn-sized type");
|
||||
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 {
|
||||
// Preserve old value.
|
||||
// We don't have to validate as we can assume the local
|
||||
// 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)?;
|
||||
}
|
||||
// Now we can call `access_mut` again, asserting it goes well,
|
||||
@ -1009,7 +1026,7 @@ pub fn force_allocation_maybe_sized(
|
||||
Place::Ptr(mplace) => (mplace, None),
|
||||
};
|
||||
// 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)]
|
||||
@ -1038,15 +1055,14 @@ pub fn allocate_str(
|
||||
) -> MPlaceTy<'tcx, M::PointerTag> {
|
||||
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 mplace =
|
||||
MemPlace { ptr: ptr.into(), align: Align::ONE, meta: MemPlaceMeta::Meta(meta) };
|
||||
let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) };
|
||||
|
||||
let ty = self.tcx.mk_ref(
|
||||
self.tcx.lifetimes.re_static,
|
||||
ty::TypeAndMut { ty: self.tcx.types.str_, mutbl },
|
||||
);
|
||||
let layout = self.layout_of(ty).unwrap();
|
||||
MPlaceTy { mplace, layout }
|
||||
MPlaceTy { mplace, layout, align: layout.align.abi }
|
||||
}
|
||||
|
||||
/// Writes the discriminant of the given variant.
|
||||
@ -1166,7 +1182,11 @@ pub(super) fn unpack_dyn_trait(
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user