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. /// 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( pub(super) fn size_and_align_of(
&self, &self,
metadata: Option<Scalar<M::PointerTag>>, metadata: Option<Scalar<M::PointerTag>>,
layout: TyLayout<'tcx>, layout: TyLayout<'tcx>,
) -> EvalResult<'tcx, (Size, Align)> { ) -> EvalResult<'tcx, Option<(Size, Align)>> {
let metadata = match metadata { if !layout.is_unsized() {
None => { return Ok(Some(layout.size_and_align()));
assert!(!layout.is_unsized()); }
return Ok(layout.size_and_align())
}
Some(metadata) => {
assert!(layout.is_unsized());
metadata
}
};
match layout.ty.sty { match layout.ty.sty {
ty::Adt(..) | ty::Tuple(..) => { ty::Adt(..) | ty::Tuple(..) => {
// First get the size of all statically known fields. // 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 // 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 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 // FIXME (#26403, #27023): We should be adding padding
// to `sized_size` (to accommodate the `unsized_align` // 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` // `(size + (align-1)) & -align`
Ok((size.abi_align(align), align)) Ok(Some((size.abi_align(align), align)))
} }
ty::Dynamic(..) => { 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. // 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 => { 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(); 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), _ => 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( pub fn size_and_align_of_mplace(
&self, &self,
mplace: MPlaceTy<'tcx, M::PointerTag> mplace: MPlaceTy<'tcx, M::PointerTag>
) -> EvalResult<'tcx, (Size, Align)> { ) -> EvalResult<'tcx, Option<(Size, Align)>> {
self.size_and_align_of(mplace.meta, mplace.layout) self.size_and_align_of(mplace.meta, mplace.layout)
} }

View file

@ -319,9 +319,9 @@ where
// Offset may need adjustment for unsized fields // Offset may need adjustment for unsized fields
let (meta, offset) = if field_layout.is_unsized() { let (meta, offset) = if field_layout.is_unsized() {
// re-use parent metadata to determine dynamic field layout // 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)) (base.meta, offset.abi_align(align))
} else { } else {
// base.meta could be present; we might be accessing a sized field of an unsized // base.meta could be present; we might be accessing a sized field of an unsized
// struct. // 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 // for safe ptrs, also check the ptr values itself
if !ty.is_unsafe_ptr() { if !ty.is_unsafe_ptr() {
// Make sure this is non-NULL and aligned // 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) { match self.memory.check_align(place.ptr, align) {
Ok(_) => {}, Ok(_) => {},
Err(err) => match err.kind { Err(err) => match err.kind {