fix union field access and DST computations and dumping of places
This commit is contained in:
parent
689c71193a
commit
0807ad19ef
@ -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),
|
||||||
|
@ -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)?;
|
||||||
|
Loading…
Reference in New Issue
Block a user