Skip to content

Commit 8f36804

Browse files
committed
Treat repr(Rust) univariant fieldless enums as a ZST (fixes #15747)
This makes all those enums be represented the same way: ```rust enum A1 { B1 } enum A2 { B2 = 0 } enum A3 { B3, C3(!) } ```
1 parent 7bfe3ae commit 8f36804

File tree

5 files changed

+78
-7
lines changed

5 files changed

+78
-7
lines changed

src/librustc/ty/layout.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -1451,11 +1451,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
14511451
// Only one variant is inhabited.
14521452
(inh_second.is_none() &&
14531453
// Representation optimizations are allowed.
1454-
!def.repr.inhibit_enum_layout_opt() &&
1455-
// Inhabited variant either has data ...
1456-
(!variants[inh_first.unwrap()].is_empty() ||
1457-
// ... or there other, uninhabited, variants.
1458-
variants.len() > 1));
1454+
!def.repr.inhibit_enum_layout_opt());
14591455
if is_struct {
14601456
// Struct, or univariant enum equivalent to a struct.
14611457
// (Typechecking will reject discriminant-sizing attrs.)
@@ -1489,6 +1485,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
14891485
return Ok(tcx.intern_layout(st));
14901486
}
14911487

1488+
// The current code for niche-filling relies on variant indices
1489+
// instead of actual discriminants, so dataful enums with
1490+
// explicit discriminants (RFC #2363) would misbehave.
14921491
let no_explicit_discriminants = def.variants.iter().enumerate()
14931492
.all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i));
14941493

src/librustc_mir/interpret/eval_context.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,23 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
669669
(Value::ByVal(_), _) => bug!("expected fat ptr"),
670670
}
671671
} else {
672+
let src_layout = self.layout_of(src.ty)?;
673+
match src_layout.variants {
674+
layout::Variants::Single { index } => {
675+
if let Some(def) = src.ty.ty_adt_def() {
676+
let discr_val = def
677+
.discriminant_for_variant(*self.tcx, index)
678+
.val;
679+
return self.write_primval(
680+
dest,
681+
PrimVal::Bytes(discr_val),
682+
dest_ty);
683+
}
684+
}
685+
layout::Variants::Tagged { .. } |
686+
layout::Variants::NicheFilling { .. } => {},
687+
}
688+
672689
let src_val = self.value_to_primval(src)?;
673690
let dest_val = self.cast_primval(src_val, src.ty, dest_ty)?;
674691
let valty = ValTy {
@@ -856,7 +873,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
856873

857874
match layout.variants {
858875
layout::Variants::Single { index } => {
859-
return Ok(index as u128);
876+
let discr_val = ty.ty_adt_def().map_or(
877+
index as u128,
878+
|def| def.discriminant_for_variant(*self.tcx, index).val);
879+
return Ok(discr_val);
860880
}
861881
layout::Variants::Tagged { .. } |
862882
layout::Variants::NicheFilling { .. } => {},

src/librustc_trans/mir/place.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,10 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
269269
}
270270
match self.layout.variants {
271271
layout::Variants::Single { index } => {
272-
return C_uint(cast_to, index as u64);
272+
let discr_val = self.layout.ty.ty_adt_def().map_or(
273+
index as u128,
274+
|def| def.discriminant_for_variant(bx.cx.tcx, index).val);
275+
return C_uint_big(cast_to, discr_val);
273276
}
274277
layout::Variants::Tagged { .. } |
275278
layout::Variants::NicheFilling { .. } => {},

src/librustc_trans/mir/rvalue.rs

+16
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,22 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
278278
.expect("bad input type for cast");
279279
let r_t_out = CastTy::from_ty(cast.ty).expect("bad output type for cast");
280280
let ll_t_in = operand.layout.immediate_llvm_type(bx.cx);
281+
match operand.layout.variants {
282+
layout::Variants::Single { index } => {
283+
if let Some(def) = operand.layout.ty.ty_adt_def() {
284+
let discr_val = def
285+
.discriminant_for_variant(bx.cx.tcx, index)
286+
.val;
287+
let discr = C_uint_big(ll_t_out, discr_val);
288+
return (bx, OperandRef {
289+
val: OperandValue::Immediate(discr),
290+
layout: cast,
291+
});
292+
}
293+
}
294+
layout::Variants::Tagged { .. } |
295+
layout::Variants::NicheFilling { .. } => {},
296+
}
281297
let llval = operand.immediate();
282298

283299
let mut signed = false;

src/test/run-pass/type-sizes.rs

+33
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,31 @@ enum ReorderedEnum {
4343
B(u8, u16, u8),
4444
}
4545

46+
enum EnumEmpty {}
47+
48+
enum EnumSingle1 {
49+
A,
50+
}
51+
52+
enum EnumSingle2 {
53+
A = 42 as isize,
54+
}
55+
56+
enum EnumSingle3 {
57+
A,
58+
B(!),
59+
}
60+
61+
#[repr(u8)]
62+
enum EnumSingle4 {
63+
A,
64+
}
65+
66+
#[repr(u8)]
67+
enum EnumSingle5 {
68+
A = 42 as u8,
69+
}
70+
4671
enum NicheFilledEnumWithInhabitedVariant {
4772
A(&'static ()),
4873
B(&'static (), !),
@@ -74,5 +99,13 @@ pub fn main() {
7499
assert_eq!(size_of::<e3>(), 4 as usize);
75100
assert_eq!(size_of::<ReorderedStruct>(), 4);
76101
assert_eq!(size_of::<ReorderedEnum>(), 6);
102+
103+
assert_eq!(size_of::<EnumEmpty>(), 0);
104+
assert_eq!(size_of::<EnumSingle1>(), 0);
105+
assert_eq!(size_of::<EnumSingle2>(), 0);
106+
assert_eq!(size_of::<EnumSingle3>(), 0);
107+
assert_eq!(size_of::<EnumSingle4>(), 1);
108+
assert_eq!(size_of::<EnumSingle5>(), 1);
109+
77110
assert_eq!(size_of::<NicheFilledEnumWithInhabitedVariant>(), size_of::<&'static ()>());
78111
}

0 commit comments

Comments
 (0)