1
Fork 0

size_and_align_of can return no result for extern types

This commit is contained in:
Ralf Jung 2018-10-09 22:41:41 +02:00
parent f79a22c3d5
commit 93f53e5113
3 changed files with 26 additions and 23 deletions

View file

@ -332,22 +332,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
}
/// Return the actual dynamic size and alignment of the place at the given type.
/// Only the `meta` part of the place matters.
/// 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(
&self,
metadata: Option<Scalar<M::PointerTag>>,
layout: TyLayout<'tcx>,
) -> EvalResult<'tcx, (Size, Align)> {
let metadata = match metadata {
None => {
assert!(!layout.is_unsized());
return Ok(layout.size_and_align())
) -> EvalResult<'tcx, Option<(Size, Align)>> {
if !layout.is_unsized() {
return Ok(Some(layout.size_and_align()));
}
Some(metadata) => {
assert!(layout.is_unsized());
metadata
}
};
match layout.ty.sty {
ty::Adt(..) | ty::Tuple(..) => {
// First get the size of all statically known fields.
@ -367,9 +361,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
);
// Recurse to get the size of the dynamically sized field (must be
// the last field).
// the last field). Can't have foreign types here, how would we
// adjust alignment and size for them?
let field = layout.field(self, layout.fields.count() - 1)?;
let (unsized_size, unsized_align) = self.size_and_align_of(Some(metadata), field)?;
let (unsized_size, unsized_align) = self.size_and_align_of(metadata, field)?
.expect("Fields cannot be extern types");
// FIXME (#26403, #27023): We should be adding padding
// to `sized_size` (to accommodate the `unsized_align`
@ -396,18 +392,22 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
//
// `(size + (align-1)) & -align`
Ok((size.abi_align(align), align))
Ok(Some((size.abi_align(align), align)))
}
ty::Dynamic(..) => {
let vtable = metadata.to_ptr()?;
let vtable = metadata.expect("dyn trait fat ptr must have vtable").to_ptr()?;
// the second entry in the vtable is the dynamic size of the object.
self.read_size_and_align_from_vtable(vtable)
Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
}
ty::Slice(_) | ty::Str => {
let len = metadata.to_usize(self)?;
let len = metadata.expect("slice fat ptr must have vtable").to_usize(self)?;
let (elem_size, align) = layout.field(self, 0)?.size_and_align();
Ok((elem_size * len, align))
Ok(Some((elem_size * len, align)))
}
ty::Foreign(_) => {
Ok(None)
}
_ => bug!("size_and_align_of::<{:?}> not supported", layout.ty),
@ -417,7 +417,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
pub fn size_and_align_of_mplace(
&self,
mplace: MPlaceTy<'tcx, M::PointerTag>
) -> EvalResult<'tcx, (Size, Align)> {
) -> EvalResult<'tcx, Option<(Size, Align)>> {
self.size_and_align_of(mplace.meta, mplace.layout)
}

View file

@ -319,9 +319,9 @@ where
// Offset may need adjustment for unsized fields
let (meta, offset) = if field_layout.is_unsized() {
// re-use parent metadata to determine dynamic field layout
let (_, align) = self.size_and_align_of(base.meta, field_layout)?;
let (_, align) = self.size_and_align_of(base.meta, field_layout)?
.expect("Fields cannot be extern types");
(base.meta, offset.abi_align(align))
} else {
// base.meta could be present; we might be accessing a sized field of an unsized
// struct.

View file

@ -208,7 +208,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
// for safe ptrs, also check the ptr values itself
if !ty.is_unsafe_ptr() {
// Make sure this is non-NULL and aligned
let (size, align) = self.size_and_align_of(place.meta, place.layout)?;
let (size, align) = self.size_and_align_of(place.meta, place.layout)?
// for the purpose of validity, consider foreign types to have
// alignment 1 and size 0.
.unwrap_or_else(|| (Size::ZERO, Align::from_bytes(1, 1).unwrap()));
match self.memory.check_align(place.ptr, align) {
Ok(_) => {},
Err(err) => match err.kind {