about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-04-26 18:26:03 +0000
committerbors <bors@rust-lang.org>2018-04-26 18:26:03 +0000
commit7f3444e1baf0d335b4bf379f845dbc28cdd0509c (patch)
treed622c175eba7e36229cd0d3cc985ce29a8f0f72c
parent949010d23e9f7037a8e6f323588873b3d2438fb1 (diff)
parent1c09977c9a1aa344c52ddf44ebd42bacd876274b (diff)
downloadrust-7f3444e1baf0d335b4bf379f845dbc28cdd0509c.tar.gz
rust-7f3444e1baf0d335b4bf379f845dbc28cdd0509c.zip
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
-rw-r--r--src/librustc/ty/layout.rs9
-rw-r--r--src/librustc_mir/interpret/eval_context.rs34
-rw-r--r--src/librustc_mir/interpret/place.rs1
-rw-r--r--src/librustc_trans/mir/place.rs18
-rw-r--r--src/librustc_trans/mir/rvalue.rs26
-rw-r--r--src/test/debuginfo/c-style-enum.rs1
-rw-r--r--src/test/run-pass/issue-23304-2.rs9
-rw-r--r--src/test/run-pass/type-sizes.rs33
8 files changed, 116 insertions, 15 deletions
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 942cfdb36b8..ef2a4246628 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -727,11 +727,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.)
@@ -765,6 +761,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 42f0e38af1f..4b57c641546 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -671,6 +671,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 {
@@ -852,10 +869,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
     ) -> EvalResult<'tcx, u128> {
         let layout = self.layout_of(ty)?;
         trace!("read_discriminant_value {:#?}", layout);
+        if layout.abi == layout::Abi::Uninhabited {
+            return Ok(0);
+        }
 
         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 { .. } => {},
@@ -1318,6 +1341,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
     pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
         use syntax::ast::FloatTy;
 
+        let layout = self.layout_of(ty)?;
+        // do the strongest layout check of the two
+        let align = layout.align.max(ptr_align);
+        self.memory.check_align(ptr, align)?;
+
+        if layout.size.bytes() == 0 {
+            return Ok(Some(Value::ByVal(PrimVal::Undef)));
+        }
+
         let ptr = ptr.to_ptr()?;
         let val = match ty.sty {
             ty::TyBool => {
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 456f5fd75db..42cb149d682 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -136,6 +136,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 let val = [a, b][field_index];
                 Ok(Some((Value::ByVal(val), field.ty)))
             },
+            // FIXME(oli-obk): figure out whether we should be calling `try_read_value` here
             _ => Ok(None),
         }
     }
diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs
index b340d91b027..b8b0c019ca6 100644
--- a/src/librustc_trans/mir/place.rs
+++ b/src/librustc_trans/mir/place.rs
@@ -16,7 +16,7 @@ use rustc::mir::tcx::PlaceTy;
 use rustc_data_structures::indexed_vec::Idx;
 use base;
 use builder::Builder;
-use common::{CodegenCx, C_usize, C_u8, C_u32, C_uint, C_int, C_null, C_uint_big};
+use common::{CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big};
 use consts;
 use type_of::LayoutLlvmExt;
 use type_::Type;
@@ -264,9 +264,15 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
     /// Obtain the actual discriminant of a value.
     pub fn trans_get_discr(self, bx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef {
         let cast_to = bx.cx.layout_of(cast_to).immediate_llvm_type(bx.cx);
+        if self.layout.abi == layout::Abi::Uninhabited {
+            return C_undef(cast_to);
+        }
         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 { .. } => {},
@@ -328,9 +334,11 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
                 let ptr = self.project_field(bx, 0);
                 let to = self.layout.ty.ty_adt_def().unwrap()
                     .discriminant_for_variant(bx.tcx(), variant_index)
-                    .val as u64;
-                bx.store(C_int(ptr.layout.llvm_type(bx.cx), to as i64),
-                    ptr.llval, ptr.align);
+                    .val;
+                bx.store(
+                    C_uint_big(ptr.layout.llvm_type(bx.cx), to),
+                    ptr.llval,
+                    ptr.align);
             }
             layout::Variants::NicheFilling {
                 dataful_variant,
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 93702bfbbf3..c932777402e 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -22,7 +22,7 @@ use base;
 use builder::Builder;
 use callee;
 use common::{self, val_ty};
-use common::{C_bool, C_u8, C_i32, C_u32, C_u64, C_null, C_usize, C_uint, C_uint_big};
+use common::{C_bool, C_u8, C_i32, C_u32, C_u64, C_undef, C_null, C_usize, C_uint, C_uint_big};
 use consts;
 use monomorphize;
 use type_::Type;
@@ -267,11 +267,33 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
                     }
                     mir::CastKind::Misc => {
                         assert!(cast.is_llvm_immediate());
+                        let ll_t_out = cast.immediate_llvm_type(bx.cx);
+                        if operand.layout.abi == layout::Abi::Uninhabited {
+                            return (bx, OperandRef {
+                                val: OperandValue::Immediate(C_undef(ll_t_out)),
+                                layout: cast,
+                            });
+                        }
                         let r_t_in = CastTy::from_ty(operand.layout.ty)
                             .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);
-                        let ll_t_out = cast.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/debuginfo/c-style-enum.rs b/src/test/debuginfo/c-style-enum.rs
index 1f1f42e2dec..2dbac8e3d9e 100644
--- a/src/test/debuginfo/c-style-enum.rs
+++ b/src/test/debuginfo/c-style-enum.rs
@@ -151,6 +151,7 @@ enum ManualDiscriminant {
 }
 
 #[derive(Copy, Clone)]
+#[repr(u8)]
 enum SingleVariant {
     TheOnlyVariant
 }
diff --git a/src/test/run-pass/issue-23304-2.rs b/src/test/run-pass/issue-23304-2.rs
index 79712f7c25e..5989b7e9c6a 100644
--- a/src/test/run-pass/issue-23304-2.rs
+++ b/src/test/run-pass/issue-23304-2.rs
@@ -10,8 +10,13 @@
 
 #![allow(dead_code)]
 
-enum X { A = 0 as isize }
+enum X { A = 42 as isize }
 
 enum Y { A = X::A as isize }
 
-fn main() { }
+fn main() {
+    let x = X::A;
+    let x = x as isize;
+    assert_eq!(x, 42);
+    assert_eq!(Y::A as isize, 42);
+}
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 ()>());
 }