make size_and_align_of_mplace work on all projectable

This commit is contained in:
Ralf Jung
2025-06-26 10:24:33 +02:00
parent 3790eff4d4
commit 7de39f55dd
9 changed files with 21 additions and 27 deletions

View File

@@ -362,7 +362,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Returns the actual dynamic size and alignment of the place at the given type.
/// Only the "meta" (metadata) part of the place matters.
/// This can fail to provide an answer for extern types.
pub(super) fn size_and_align_of(
pub(super) fn size_and_align_from_meta(
&self,
metadata: &MemPlaceMeta<M::Provenance>,
layout: &TyAndLayout<'tcx>,
@@ -388,7 +388,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// adjust alignment and size for them?
let field = layout.field(self, layout.fields.count() - 1);
let Some((unsized_size, mut unsized_align)) =
self.size_and_align_of(metadata, &field)?
self.size_and_align_from_meta(metadata, &field)?
else {
// A field with an extern type. We don't know the actual dynamic size
// or the alignment.
@@ -450,11 +450,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
}
#[inline]
pub fn size_and_align_of_mplace(
pub fn size_and_align_of_val(
&self,
mplace: &MPlaceTy<'tcx, M::Provenance>,
val: &impl Projectable<'tcx, M::Provenance>,
) -> InterpResult<'tcx, Option<(Size, Align)>> {
self.size_and_align_of(&mplace.meta(), &mplace.layout)
self.size_and_align_from_meta(&val.meta(), &val.layout())
}
/// Jump to the given block.

View File

@@ -125,7 +125,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// dereferenceable!
let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?;
let (size, align) = self
.size_and_align_of_mplace(&place)?
.size_and_align_of_val(&place)?
.ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?;
let result = match intrinsic_name {

View File

@@ -470,7 +470,7 @@ where
) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
{
let (size, _align) = self
.size_and_align_of_mplace(mplace)?
.size_and_align_of_val(mplace)?
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
// We check alignment separately, and *after* checking everything else.
// If an access is both OOB and misaligned, we want to see the bounds error.
@@ -486,7 +486,7 @@ where
) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
{
let (size, _align) = self
.size_and_align_of_mplace(mplace)?
.size_and_align_of_val(mplace)?
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
// We check alignment separately, and raise that error *after* checking everything else.
// If an access is both OOB and misaligned, we want to see the bounds error.
@@ -888,11 +888,11 @@ where
trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout().ty);
let dest = dest.force_mplace(self)?;
let Some((dest_size, _)) = self.size_and_align_of_mplace(&dest)? else {
let Some((dest_size, _)) = self.size_and_align_of_val(&dest)? else {
span_bug!(self.cur_span(), "copy_op needs (dynamically) sized values")
};
if cfg!(debug_assertions) {
let src_size = self.size_and_align_of_mplace(&src)?.unwrap().0;
let src_size = self.size_and_align_of_val(&src)?.unwrap().0;
assert_eq!(src_size, dest_size, "Cannot copy differently-sized data");
} else {
// As a cheap approximation, we compare the fixed parts of the size.
@@ -980,7 +980,7 @@ where
kind: MemoryKind<M::MemoryKind>,
meta: MemPlaceMeta<M::Provenance>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
let Some((size, align)) = self.size_and_align_of(&meta, &layout)? else {
let Some((size, align)) = self.size_and_align_from_meta(&meta, &layout)? else {
span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known")
};
let ptr = self.allocate_ptr(size, align, kind, AllocInit::Uninit)?;

View File

@@ -168,7 +168,7 @@ where
// 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)? {
match self.size_and_align_from_meta(&base_meta, &field_layout)? {
Some((_, align)) => {
// For packed types, we need to cap alignment.
let align = if let ty::Adt(def, _) = base.layout().ty.kind()

View File

@@ -493,7 +493,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
}
// Make sure this is dereferenceable and all.
let size_and_align = try_validation!(
self.ecx.size_and_align_of_mplace(&place),
self.ecx.size_and_align_of_val(&place),
self.path,
Ub(InvalidMeta(msg)) => match msg {
InvalidMetaKind::SliceTooBig => InvalidMetaSliceTooLarge { ptr_kind },
@@ -906,7 +906,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
let (_prov, start_offset) = mplace.ptr().into_parts();
let (size, _align) = self
.ecx
.size_and_align_of_mplace(&mplace)?
.size_and_align_of_val(&mplace)?
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
// If there is no padding at all, we can skip the rest: check for
// a single data range covering the entire value.
@@ -1088,10 +1088,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) {
// Unsized unions are currently not a thing, but let's keep this code consistent with
// the check in `visit_value`.
let zst = self
.ecx
.size_and_align_of(&val.meta(), &val.layout)?
.is_some_and(|(s, _a)| s.bytes() == 0);
let zst = self.ecx.size_and_align_of_val(val)?.is_some_and(|(s, _a)| s.bytes() == 0);
if !zst && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.typing_env) {
if !self.in_mutable_memory(val) {
throw_validation_failure!(self.path, UnsafeCellInImmutable);
@@ -1138,10 +1135,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) {
// Exclude ZST values. We need to compute the dynamic size/align to properly
// handle slices and trait objects.
let zst = self
.ecx
.size_and_align_of(&val.meta(), &val.layout)?
.is_some_and(|(s, _a)| s.bytes() == 0);
let zst = self.ecx.size_and_align_of_val(val)?.is_some_and(|(s, _a)| s.bytes() == 0);
if !zst
&& let Some(def) = val.layout.ty.ty_adt_def()
&& def.is_unsafe_cell()