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:
parent
7bfe3ae00a
commit
8f36804c00
5 changed files with 78 additions and 7 deletions
|
@ -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));
|
||||
|
||||
|
|
|
@ -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 { .. } => {},
|
||||
|
|
|
@ -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 { .. } => {},
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ()>());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue