about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAnthony Ramine <n.oxyde@gmail.com>2018-03-30 15:49:56 +0200
committerAnthony Ramine <n.oxyde@gmail.com>2018-04-26 16:22:18 +0200
commit8f36804c00ca11ca9b4ed111dc4b4066b940508e (patch)
tree1bab393e295a519c8f6ac71c1a91b13e58ba9738 /src
parent7bfe3ae00a36e8162e2f8f5b47eb7127562e1d17 (diff)
downloadrust-8f36804c00ca11ca9b4ed111dc4b4066b940508e.tar.gz
rust-8f36804c00ca11ca9b4ed111dc4b4066b940508e.zip
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(!) }
```
Diffstat (limited to 'src')
-rw-r--r--src/librustc/ty/layout.rs9
-rw-r--r--src/librustc_mir/interpret/eval_context.rs22
-rw-r--r--src/librustc_trans/mir/place.rs5
-rw-r--r--src/librustc_trans/mir/rvalue.rs16
-rw-r--r--src/test/run-pass/type-sizes.rs33
5 files changed, 78 insertions, 7 deletions
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 77e2e9447f1..7dec180c5a7 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -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));
 
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index a7cd044cec0..00f90573682 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -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 { .. } => {},
diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs
index c39612e3ab0..b8b0c019ca6 100644
--- a/src/librustc_trans/mir/place.rs
+++ b/src/librustc_trans/mir/place.rs
@@ -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 { .. } => {},
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 245f3ec11c9..c932777402e 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -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;
diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs
index 7bd9a1703ee..a47f082b9c3 100644
--- a/src/test/run-pass/type-sizes.rs
+++ b/src/test/run-pass/type-sizes.rs
@@ -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 ()>());
 }