Skip to content

Commit 3554f2d

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 5d39517 + 74608c7 commit 3554f2d

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
@@ -780,8 +780,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
780780
present_first @ Some(_) => present_first,
781781
// Uninhabited because it has no variants, or only absent ones.
782782
None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)),
783-
// if it's a struct, still compute a layout so that we can still compute the
784-
// field offsets
783+
// If it's a struct, still compute a layout so that we can still compute the
784+
// field offsets.
785785
None => Some(VariantIdx::new(0)),
786786
};
787787

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

19922000
Variants::Single { index } => {
19932001
// 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
@@ -355,7 +355,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
355355
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
356356
let base = match op.try_as_mplace(self) {
357357
Ok(mplace) => {
358-
// The easy case
358+
// We can reuse the mplace field computation logic for indirect operands.
359359
let field = self.mplace_field(mplace, field)?;
360360
return Ok(field.into());
361361
}

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)