diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index b0b8962b76a..bc613358152 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -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>, 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. @@ -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) } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 55077c8b6f9..923f0dc4c29 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -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. diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index cff4a0a323e..0c1dc092ce1 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -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 {