1
Fork 0

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(!) }
```
This commit is contained in:
Anthony Ramine 2018-03-30 15:49:56 +02:00
parent 7bfe3ae00a
commit 8f36804c00
5 changed files with 78 additions and 7 deletions

View file

@ -1451,11 +1451,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
// Only one variant is inhabited.
(inh_second.is_none() &&
// Representation optimizations are allowed.
!def.repr.inhibit_enum_layout_opt() &&
// Inhabited variant either has data ...
(!variants[inh_first.unwrap()].is_empty() ||
// ... or there other, uninhabited, variants.
variants.len() > 1));
!def.repr.inhibit_enum_layout_opt());
if is_struct {
// Struct, or univariant enum equivalent to a struct.
// (Typechecking will reject discriminant-sizing attrs.)
@ -1489,6 +1485,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
return Ok(tcx.intern_layout(st));
}
// The current code for niche-filling relies on variant indices
// instead of actual discriminants, so dataful enums with
// explicit discriminants (RFC #2363) would misbehave.
let no_explicit_discriminants = def.variants.iter().enumerate()
.all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i));

View file

@ -669,6 +669,23 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
(Value::ByVal(_), _) => bug!("expected fat ptr"),
}
} else {
let src_layout = self.layout_of(src.ty)?;
match src_layout.variants {
layout::Variants::Single { index } => {
if let Some(def) = src.ty.ty_adt_def() {
let discr_val = def
.discriminant_for_variant(*self.tcx, index)
.val;
return self.write_primval(
dest,
PrimVal::Bytes(discr_val),
dest_ty);
}
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => {},
}
let src_val = self.value_to_primval(src)?;
let dest_val = self.cast_primval(src_val, src.ty, dest_ty)?;
let valty = ValTy {
@ -856,7 +873,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
match layout.variants {
layout::Variants::Single { index } => {
return Ok(index as u128);
let discr_val = ty.ty_adt_def().map_or(
index as u128,
|def| def.discriminant_for_variant(*self.tcx, index).val);
return Ok(discr_val);
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => {},

View file

@ -269,7 +269,10 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
}
match self.layout.variants {
layout::Variants::Single { index } => {
return C_uint(cast_to, index as u64);
let discr_val = self.layout.ty.ty_adt_def().map_or(
index as u128,
|def| def.discriminant_for_variant(bx.cx.tcx, index).val);
return C_uint_big(cast_to, discr_val);
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => {},

View file

@ -278,6 +278,22 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
.expect("bad input type for cast");
let r_t_out = CastTy::from_ty(cast.ty).expect("bad output type for cast");
let ll_t_in = operand.layout.immediate_llvm_type(bx.cx);
match operand.layout.variants {
layout::Variants::Single { index } => {
if let Some(def) = operand.layout.ty.ty_adt_def() {
let discr_val = def
.discriminant_for_variant(bx.cx.tcx, index)
.val;
let discr = C_uint_big(ll_t_out, discr_val);
return (bx, OperandRef {
val: OperandValue::Immediate(discr),
layout: cast,
});
}
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => {},
}
let llval = operand.immediate();
let mut signed = false;

View file

@ -43,6 +43,31 @@ enum ReorderedEnum {
B(u8, u16, u8),
}
enum EnumEmpty {}
enum EnumSingle1 {
A,
}
enum EnumSingle2 {
A = 42 as isize,
}
enum EnumSingle3 {
A,
B(!),
}
#[repr(u8)]
enum EnumSingle4 {
A,
}
#[repr(u8)]
enum EnumSingle5 {
A = 42 as u8,
}
enum NicheFilledEnumWithInhabitedVariant {
A(&'static ()),
B(&'static (), !),
@ -74,5 +99,13 @@ pub fn main() {
assert_eq!(size_of::<e3>(), 4 as usize);
assert_eq!(size_of::<ReorderedStruct>(), 4);
assert_eq!(size_of::<ReorderedEnum>(), 6);
assert_eq!(size_of::<EnumEmpty>(), 0);
assert_eq!(size_of::<EnumSingle1>(), 0);
assert_eq!(size_of::<EnumSingle2>(), 0);
assert_eq!(size_of::<EnumSingle3>(), 0);
assert_eq!(size_of::<EnumSingle4>(), 1);
assert_eq!(size_of::<EnumSingle5>(), 1);
assert_eq!(size_of::<NicheFilledEnumWithInhabitedVariant>(), size_of::<&'static ()>());
}