Skip to content

Commit 7f3444e

Browse files
committed
Auto merge of #49513 - nox:univariant-fieldless-enum-as-zst, r=eddyb
Treat repr(Rust) univariant fieldless enums as ZSTs This makes all those enums be represented the same way: ```rust enum A1 { B1 } enum A2 { B2 = 0 } enum A3 { B3, C3(!) } ``` Related to #15747. Cc @rust-lang/wg-codegen @rust-lang/lang
2 parents 949010d + 1c09977 commit 7f3444e

File tree

8 files changed

+116
-15
lines changed

8 files changed

+116
-15
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

+33-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 {
@@ -852,10 +869,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
852869
) -> EvalResult<'tcx, u128> {
853870
let layout = self.layout_of(ty)?;
854871
trace!("read_discriminant_value {:#?}", layout);
872+
if layout.abi == layout::Abi::Uninhabited {
873+
return Ok(0);
874+
}
855875

856876
match layout.variants {
857877
layout::Variants::Single { index } => {
858-
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);
859882
}
860883
layout::Variants::Tagged { .. } |
861884
layout::Variants::NicheFilling { .. } => {},
@@ -1318,6 +1341,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
13181341
pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
13191342
use syntax::ast::FloatTy;
13201343

1344+
let layout = self.layout_of(ty)?;
1345+
// do the strongest layout check of the two
1346+
let align = layout.align.max(ptr_align);
1347+
self.memory.check_align(ptr, align)?;
1348+
1349+
if layout.size.bytes() == 0 {
1350+
return Ok(Some(Value::ByVal(PrimVal::Undef)));
1351+
}
1352+
13211353
let ptr = ptr.to_ptr()?;
13221354
let val = match ty.sty {
13231355
ty::TyBool => {

src/librustc_mir/interpret/place.rs

+1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
136136
let val = [a, b][field_index];
137137
Ok(Some((Value::ByVal(val), field.ty)))
138138
},
139+
// FIXME(oli-obk): figure out whether we should be calling `try_read_value` here
139140
_ => Ok(None),
140141
}
141142
}

src/librustc_trans/mir/place.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc::mir::tcx::PlaceTy;
1616
use rustc_data_structures::indexed_vec::Idx;
1717
use base;
1818
use builder::Builder;
19-
use common::{CodegenCx, C_usize, C_u8, C_u32, C_uint, C_int, C_null, C_uint_big};
19+
use common::{CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big};
2020
use consts;
2121
use type_of::LayoutLlvmExt;
2222
use type_::Type;
@@ -264,9 +264,15 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
264264
/// Obtain the actual discriminant of a value.
265265
pub fn trans_get_discr(self, bx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef {
266266
let cast_to = bx.cx.layout_of(cast_to).immediate_llvm_type(bx.cx);
267+
if self.layout.abi == layout::Abi::Uninhabited {
268+
return C_undef(cast_to);
269+
}
267270
match self.layout.variants {
268271
layout::Variants::Single { index } => {
269-
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);
270276
}
271277
layout::Variants::Tagged { .. } |
272278
layout::Variants::NicheFilling { .. } => {},
@@ -328,9 +334,11 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
328334
let ptr = self.project_field(bx, 0);
329335
let to = self.layout.ty.ty_adt_def().unwrap()
330336
.discriminant_for_variant(bx.tcx(), variant_index)
331-
.val as u64;
332-
bx.store(C_int(ptr.layout.llvm_type(bx.cx), to as i64),
333-
ptr.llval, ptr.align);
337+
.val;
338+
bx.store(
339+
C_uint_big(ptr.layout.llvm_type(bx.cx), to),
340+
ptr.llval,
341+
ptr.align);
334342
}
335343
layout::Variants::NicheFilling {
336344
dataful_variant,

src/librustc_trans/mir/rvalue.rs

+24-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use base;
2222
use builder::Builder;
2323
use callee;
2424
use common::{self, val_ty};
25-
use common::{C_bool, C_u8, C_i32, C_u32, C_u64, C_null, C_usize, C_uint, C_uint_big};
25+
use common::{C_bool, C_u8, C_i32, C_u32, C_u64, C_undef, C_null, C_usize, C_uint, C_uint_big};
2626
use consts;
2727
use monomorphize;
2828
use type_::Type;
@@ -267,11 +267,33 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
267267
}
268268
mir::CastKind::Misc => {
269269
assert!(cast.is_llvm_immediate());
270+
let ll_t_out = cast.immediate_llvm_type(bx.cx);
271+
if operand.layout.abi == layout::Abi::Uninhabited {
272+
return (bx, OperandRef {
273+
val: OperandValue::Immediate(C_undef(ll_t_out)),
274+
layout: cast,
275+
});
276+
}
270277
let r_t_in = CastTy::from_ty(operand.layout.ty)
271278
.expect("bad input type for cast");
272279
let r_t_out = CastTy::from_ty(cast.ty).expect("bad output type for cast");
273280
let ll_t_in = operand.layout.immediate_llvm_type(bx.cx);
274-
let ll_t_out = cast.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+
}
275297
let llval = operand.immediate();
276298

277299
let mut signed = false;

src/test/debuginfo/c-style-enum.rs

+1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ enum ManualDiscriminant {
151151
}
152152

153153
#[derive(Copy, Clone)]
154+
#[repr(u8)]
154155
enum SingleVariant {
155156
TheOnlyVariant
156157
}

src/test/run-pass/issue-23304-2.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@
1010

1111
#![allow(dead_code)]
1212

13-
enum X { A = 0 as isize }
13+
enum X { A = 42 as isize }
1414

1515
enum Y { A = X::A as isize }
1616

17-
fn main() { }
17+
fn main() {
18+
let x = X::A;
19+
let x = x as isize;
20+
assert_eq!(x, 42);
21+
assert_eq!(Y::A as isize, 42);
22+
}

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)