size_and_align_of can return no result for extern types
This commit is contained in:
parent
f79a22c3d5
commit
93f53e5113
3 changed files with 26 additions and 23 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue