Skip to content

Commit 7210c6c

Browse files
authored
Rollup merge of rust-lang#69768 - oli-obk:union_field_ice, r=eddyb,RalfJung
Compute the correct layout for variants of uninhabited enums r? @eddyb cc @RalfJung fixes rust-lang#69191 cc rust-lang#69763
2 parents e10e6f0 + 74608c7 commit 7210c6c

File tree

4 files changed

+16
-13
lines changed

4 files changed

+16
-13
lines changed

src/librustc/ty/layout.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -782,8 +782,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
782782
present_first @ Some(_) => present_first,
783783
// Uninhabited because it has no variants, or only absent ones.
784784
None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)),
785-
// if it's a struct, still compute a layout so that we can still compute the
786-
// field offsets
785+
// If it's a struct, still compute a layout so that we can still compute the
786+
// field offsets.
787787
None => Some(VariantIdx::new(0)),
788788
};
789789

@@ -1990,7 +1990,15 @@ where
19901990
{
19911991
fn for_variant(this: TyLayout<'tcx>, cx: &C, variant_index: VariantIdx) -> TyLayout<'tcx> {
19921992
let details = match this.variants {
1993-
Variants::Single { index } if index == variant_index => this.details,
1993+
Variants::Single { index }
1994+
// If all variants but one are uninhabited, the variant layout is the enum layout.
1995+
if index == variant_index &&
1996+
// Don't confuse variants of uninhabited enums with the enum itself.
1997+
// For more details see https://github.com/rust-lang/rust/issues/69763.
1998+
this.fields != FieldPlacement::Union(0) =>
1999+
{
2000+
this.details
2001+
}
19942002

19952003
Variants::Single { index } => {
19962004
// Deny calling for_variant more than once for non-Single enums.

src/librustc_mir/interpret/operand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
356356
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
357357
let base = match op.try_as_mplace(self) {
358358
Ok(mplace) => {
359-
// The easy case
359+
// We can reuse the mplace field computation logic for indirect operands.
360360
let field = self.mplace_field(mplace, field)?;
361361
return Ok(field.into());
362362
}

src/librustc_mir/interpret/place.rs

-8
Original file line numberDiff line numberDiff line change
@@ -410,14 +410,6 @@ where
410410
stride * field
411411
}
412412
layout::FieldPlacement::Union(count) => {
413-
// This is a narrow bug-fix for rust-lang/rust#69191: if we are
414-
// trying to access absent field of uninhabited variant, then
415-
// signal UB (but don't ICE the compiler).
416-
// FIXME temporary hack to work around incoherence between
417-
// layout computation and MIR building
418-
if field >= count as u64 && base.layout.abi == layout::Abi::Uninhabited {
419-
throw_ub!(Unreachable);
420-
}
421413
assert!(
422414
field < count as u64,
423415
"Tried to access field {} of union {:#?} with {} fields",

src/librustc_target/abi/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,10 @@ impl FieldPlacement {
660660

661661
pub fn offset(&self, i: usize) -> Size {
662662
match *self {
663-
FieldPlacement::Union(_) => Size::ZERO,
663+
FieldPlacement::Union(count) => {
664+
assert!(i < count, "tried to access field {} of union with {} fields", i, count);
665+
Size::ZERO
666+
}
664667
FieldPlacement::Array { stride, count } => {
665668
let i = i as u64;
666669
assert!(i < count);

0 commit comments

Comments
 (0)