}
/// 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())
- }
- Some(metadata) => {
- assert!(layout.is_unsized());
- metadata
- }
- };
+ ) -> EvalResult<'tcx, Option<(Size, Align)>> {
+ if !layout.is_unsized() {
+ return Ok(Some(layout.size_and_align()));
+ }
match layout.ty.sty {
ty::Adt(..) | ty::Tuple(..) => {
// First get the size of all statically known fields.
);
// 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`
//
// `(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),
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)
}
// 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.
// 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 {