fix union field access and DST computations and dumping of places

This commit is contained in:
Ralf Jung 2018-08-15 20:22:28 +02:00
parent 689c71193a
commit 0807ad19ef
2 changed files with 33 additions and 27 deletions

View File

@ -465,36 +465,38 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
/// Return the size and alignment of the value at the given type. /// Return the size and alignment of the value at the given type.
/// Note that the value does not matter if the type is sized. For unsized types, /// Note that the value does not matter if the type is sized. For unsized types,
/// the value has to be a fat pointer, and we only care about the "extra" data in it. /// the value has to be a fat pointer, and we only care about the "extra" data in it.
pub fn size_and_align_of_dst( pub fn size_and_align_of_val(
&self, &self,
val: ValTy<'tcx>, val: ValTy<'tcx>,
) -> EvalResult<'tcx, (Size, Align)> { ) -> EvalResult<'tcx, (Size, Align)> {
if !val.layout.is_unsized() { let pointee_ty = val.layout.ty.builtin_deref(true).unwrap().ty;
Ok(val.layout.size_and_align()) let layout = self.layout_of(pointee_ty)?;
if !layout.is_unsized() {
Ok(layout.size_and_align())
} else { } else {
match val.layout.ty.sty { match layout.ty.sty {
ty::TyAdt(..) | ty::TyTuple(..) => { ty::TyAdt(..) | ty::TyTuple(..) => {
// First get the size of all statically known fields. // First get the size of all statically known fields.
// Don't use type_of::sizing_type_of because that expects t to be sized, // Don't use type_of::sizing_type_of because that expects t to be sized,
// and it also rounds up to alignment, which we want to avoid, // and it also rounds up to alignment, which we want to avoid,
// as the unsized field's alignment could be smaller. // as the unsized field's alignment could be smaller.
assert!(!val.layout.ty.is_simd()); assert!(!layout.ty.is_simd());
debug!("DST layout: {:?}", val.layout); debug!("DST layout: {:?}", layout);
let sized_size = val.layout.fields.offset(val.layout.fields.count() - 1); let sized_size = layout.fields.offset(layout.fields.count() - 1);
let sized_align = val.layout.align; let sized_align = layout.align;
debug!( debug!(
"DST {} statically sized prefix size: {:?} align: {:?}", "DST {} statically sized prefix size: {:?} align: {:?}",
val.layout.ty, layout.ty,
sized_size, sized_size,
sized_align sized_align
); );
// 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).
let field_layout = val.layout.field(self, val.layout.fields.count() - 1)?; let field_layout = layout.field(self, layout.fields.count() - 1)?;
let (unsized_size, unsized_align) = let (unsized_size, unsized_align) =
self.size_and_align_of_dst(ValTy { self.size_and_align_of_val(ValTy {
value: val.value, value: val.value,
layout: field_layout layout: field_layout
})?; })?;
@ -533,12 +535,12 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
} }
ty::TySlice(_) | ty::TyStr => { ty::TySlice(_) | ty::TyStr => {
let (elem_size, align) = val.layout.field(self, 0)?.size_and_align(); let (elem_size, align) = layout.field(self, 0)?.size_and_align();
let (_, len) = val.to_scalar_slice(self)?; let (_, len) = val.to_scalar_slice(self)?;
Ok((elem_size * len, align)) Ok((elem_size * len, align))
} }
_ => bug!("size_of_val::<{:?}>", val.layout.ty), _ => bug!("size_of_val::<{:?}>", layout.ty),
} }
} }
} }
@ -963,10 +965,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
self.memory.dump_allocs(allocs); self.memory.dump_allocs(allocs);
} }
Place::Ptr(mplace) => { Place::Ptr(mplace) => {
let (ptr, align) = mplace.to_scalar_ptr_align(); match mplace.ptr {
match ptr {
Scalar::Ptr(ptr) => { Scalar::Ptr(ptr) => {
trace!("by align({}) ref:", align.abi()); trace!("by align({}) ref:", mplace.align.abi());
self.memory.dump_alloc(ptr.alloc_id); self.memory.dump_alloc(ptr.alloc_id);
} }
ptr => trace!(" integral by ref: {:?}", ptr), ptr => trace!(" integral by ref: {:?}", ptr),

View File

@ -7,7 +7,7 @@ use std::convert::TryFrom;
use rustc::mir; use rustc::mir;
use rustc::ty::{self, Ty}; use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, HasDataLayout}; use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
use rustc::mir::interpret::{ use rustc::mir::interpret::{
@ -275,22 +275,27 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
assert!(field < len, "Tried to access element {} of array/slice with length {}", field, len); assert!(field < len, "Tried to access element {} of array/slice with length {}", field, len);
stride * field stride * field
} }
_ => bug!("Unexpected layout for field access: {:#?}", base.layout), layout::FieldPlacement::Union(count) => {
assert!(field < count as u64, "Tried to access field {} of union with {} fields", field, count);
// Offset is always 0
Size::from_bytes(0)
}
}; };
// the only way conversion can fail if is this is an array (otherwise we already panicked // the only way conversion can fail if is this is an array (otherwise we already panicked
// above). In that case, all fields are equal. // above). In that case, all fields are equal.
let field = base.layout.field(self, usize::try_from(field).unwrap_or(0))?; let field = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
// Adjust offset // Adjust offset
let offset = match base.extra { let offset = if field.is_unsized() {
PlaceExtra::Vtable(tab) => { let vtable = match base.extra {
let (_, align) = self.size_and_align_of_dst(ValTy { PlaceExtra::Vtable(tab) => tab,
layout: base.layout, _ => bug!("Unsized place with unsized field must come with vtable"),
value: Value::new_dyn_trait(base.ptr, tab), };
})?; let (_, align) = self.read_size_and_align_from_vtable(vtable)?;
offset.abi_align(align) offset.abi_align(align)
} } else {
_ => offset, // No adjustment needed
offset
}; };
let ptr = base.ptr.ptr_offset(offset, self)?; let ptr = base.ptr.ptr_offset(offset, self)?;