Skip to content

Commit 0807ad1

Browse files
committed
fix union field access and DST computations and dumping of places
1 parent 689c711 commit 0807ad1

File tree

2 files changed

+33
-27
lines changed

2 files changed

+33
-27
lines changed

src/librustc_mir/interpret/eval_context.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -465,36 +465,38 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
465465
/// Return the size and alignment of the value at the given type.
466466
/// Note that the value does not matter if the type is sized. For unsized types,
467467
/// the value has to be a fat pointer, and we only care about the "extra" data in it.
468-
pub fn size_and_align_of_dst(
468+
pub fn size_and_align_of_val(
469469
&self,
470470
val: ValTy<'tcx>,
471471
) -> EvalResult<'tcx, (Size, Align)> {
472-
if !val.layout.is_unsized() {
473-
Ok(val.layout.size_and_align())
472+
let pointee_ty = val.layout.ty.builtin_deref(true).unwrap().ty;
473+
let layout = self.layout_of(pointee_ty)?;
474+
if !layout.is_unsized() {
475+
Ok(layout.size_and_align())
474476
} else {
475-
match val.layout.ty.sty {
477+
match layout.ty.sty {
476478
ty::TyAdt(..) | ty::TyTuple(..) => {
477479
// First get the size of all statically known fields.
478480
// Don't use type_of::sizing_type_of because that expects t to be sized,
479481
// and it also rounds up to alignment, which we want to avoid,
480482
// as the unsized field's alignment could be smaller.
481-
assert!(!val.layout.ty.is_simd());
482-
debug!("DST layout: {:?}", val.layout);
483+
assert!(!layout.ty.is_simd());
484+
debug!("DST layout: {:?}", layout);
483485

484-
let sized_size = val.layout.fields.offset(val.layout.fields.count() - 1);
485-
let sized_align = val.layout.align;
486+
let sized_size = layout.fields.offset(layout.fields.count() - 1);
487+
let sized_align = layout.align;
486488
debug!(
487489
"DST {} statically sized prefix size: {:?} align: {:?}",
488-
val.layout.ty,
490+
layout.ty,
489491
sized_size,
490492
sized_align
491493
);
492494

493495
// Recurse to get the size of the dynamically sized field (must be
494496
// the last field).
495-
let field_layout = val.layout.field(self, val.layout.fields.count() - 1)?;
497+
let field_layout = layout.field(self, layout.fields.count() - 1)?;
496498
let (unsized_size, unsized_align) =
497-
self.size_and_align_of_dst(ValTy {
499+
self.size_and_align_of_val(ValTy {
498500
value: val.value,
499501
layout: field_layout
500502
})?;
@@ -533,12 +535,12 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
533535
}
534536

535537
ty::TySlice(_) | ty::TyStr => {
536-
let (elem_size, align) = val.layout.field(self, 0)?.size_and_align();
538+
let (elem_size, align) = layout.field(self, 0)?.size_and_align();
537539
let (_, len) = val.to_scalar_slice(self)?;
538540
Ok((elem_size * len, align))
539541
}
540542

541-
_ => bug!("size_of_val::<{:?}>", val.layout.ty),
543+
_ => bug!("size_of_val::<{:?}>", layout.ty),
542544
}
543545
}
544546
}
@@ -963,10 +965,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
963965
self.memory.dump_allocs(allocs);
964966
}
965967
Place::Ptr(mplace) => {
966-
let (ptr, align) = mplace.to_scalar_ptr_align();
967-
match ptr {
968+
match mplace.ptr {
968969
Scalar::Ptr(ptr) => {
969-
trace!("by align({}) ref:", align.abi());
970+
trace!("by align({}) ref:", mplace.align.abi());
970971
self.memory.dump_alloc(ptr.alloc_id);
971972
}
972973
ptr => trace!(" integral by ref: {:?}", ptr),

src/librustc_mir/interpret/place.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::convert::TryFrom;
77

88
use rustc::mir;
99
use rustc::ty::{self, Ty};
10-
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, HasDataLayout};
10+
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
1111
use rustc_data_structures::indexed_vec::Idx;
1212

1313
use rustc::mir::interpret::{
@@ -275,22 +275,27 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
275275
assert!(field < len, "Tried to access element {} of array/slice with length {}", field, len);
276276
stride * field
277277
}
278-
_ => bug!("Unexpected layout for field access: {:#?}", base.layout),
278+
layout::FieldPlacement::Union(count) => {
279+
assert!(field < count as u64, "Tried to access field {} of union with {} fields", field, count);
280+
// Offset is always 0
281+
Size::from_bytes(0)
282+
}
279283
};
280284
// the only way conversion can fail if is this is an array (otherwise we already panicked
281285
// above). In that case, all fields are equal.
282286
let field = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
283287

284288
// Adjust offset
285-
let offset = match base.extra {
286-
PlaceExtra::Vtable(tab) => {
287-
let (_, align) = self.size_and_align_of_dst(ValTy {
288-
layout: base.layout,
289-
value: Value::new_dyn_trait(base.ptr, tab),
290-
})?;
291-
offset.abi_align(align)
292-
}
293-
_ => offset,
289+
let offset = if field.is_unsized() {
290+
let vtable = match base.extra {
291+
PlaceExtra::Vtable(tab) => tab,
292+
_ => bug!("Unsized place with unsized field must come with vtable"),
293+
};
294+
let (_, align) = self.read_size_and_align_from_vtable(vtable)?;
295+
offset.abi_align(align)
296+
} else {
297+
// No adjustment needed
298+
offset
294299
};
295300

296301
let ptr = base.ptr.ptr_offset(offset, self)?;

0 commit comments

Comments
 (0)