Skip to content

Commit 2ebda12

Browse files
noxXandkeeper
authored andcommitted
Treat repr(Rust) univariant fieldless enums as a ZST (fixes rust-lang#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 8e6a748 commit 2ebda12

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
@@ -727,11 +727,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
727727
// Only one variant is inhabited.
728728
(inh_second.is_none() &&
729729
// Representation optimizations are allowed.
730-
!def.repr.inhibit_enum_layout_opt() &&
731-
// Inhabited variant either has data ...
732-
(!variants[inh_first.unwrap()].is_empty() ||
733-
// ... or there other, uninhabited, variants.
734-
variants.len() > 1));
730+
!def.repr.inhibit_enum_layout_opt());
735731
if is_struct {
736732
// Struct, or univariant enum equivalent to a struct.
737733
// (Typechecking will reject discriminant-sizing attrs.)
@@ -765,6 +761,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
765761
return Ok(tcx.intern_layout(st));
766762
}
767763

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

src/librustc_mir/interpret/eval_context.rs

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

859876
match layout.variants {
860877
layout::Variants::Single { index } => {
861-
return Ok(index as u128);
878+
let discr_val = ty.ty_adt_def().map_or(
879+
index as u128,
880+
|def| def.discriminant_for_variant(*self.tcx, index).val);
881+
return Ok(discr_val);
862882
}
863883
layout::Variants::Tagged { .. } |
864884
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)