about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/ty/layout.rs186
-rw-r--r--src/librustc_lint/types.rs4
-rw-r--r--src/librustc_trans/cabi_x86_64.rs22
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs98
-rw-r--r--src/librustc_trans/intrinsic.rs7
-rw-r--r--src/librustc_trans/mir/constant.rs41
-rw-r--r--src/librustc_trans/mir/lvalue.rs38
-rw-r--r--src/librustc_trans/mir/rvalue.rs9
-rw-r--r--src/librustc_trans/type_of.rs19
9 files changed, 188 insertions, 236 deletions
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index dbad77b904e..bfde8a58e49 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -769,33 +769,17 @@ impl Abi {
     }
 }
 
-/// Type layout, from which size and alignment can be cheaply computed.
-/// For ADTs, it also includes field placement and enum optimizations.
-/// NOTE: Because Layout is interned, redundant information should be
-/// kept to a minimum, e.g. it includes no sub-component Ty or Layout.
 #[derive(PartialEq, Eq, Hash, Debug)]
-pub enum Layout {
-    /// TyBool, TyChar, TyInt, TyUint, TyFloat, TyRawPtr, TyRef or TyFnPtr.
-    Scalar,
-
-    /// SIMD vectors, from structs marked with #[repr(simd)].
-    Vector,
-
-    /// TyArray, TySlice or TyStr.
-    Array,
-
-    // Remaining variants are all ADTs such as structs, enums or tuples.
-
-    /// Single-case enums, and structs/tuples.
-    Univariant,
-
-    /// Untagged unions.
-    UntaggedUnion,
+pub enum Variants {
+    /// Single enum variants, structs/tuples, unions, and all non-ADTs.
+    Single {
+        index: usize
+    },
 
     /// General-case enums: for each case there is a struct, and they all have
     /// all space reserved for the discriminant, and their first field starts
     /// at a non-0 offset, after where the discriminant would go.
-    General {
+    Tagged {
         discr: Primitive,
         /// Inclusive wrap-around range of discriminant values, that is,
         /// if min > max, it represents min..=u64::MAX followed by 0..=max.
@@ -806,7 +790,7 @@ pub enum Layout {
         variants: Vec<CachedLayout>,
     },
 
-    /// Two cases distinguished by a nullable pointer: the case with discriminant
+    /// Two cases distinguished by a niche: the case with discriminant
     /// `nndiscr` is represented by the struct `nonnull`, where field `0`
     /// is known to be nonnull due to its type; if that field is null, then
     /// it represents the other case, which is known to be zero sized.
@@ -814,7 +798,7 @@ pub enum Layout {
     /// For example, `std::option::Option` instantiated at a safe pointer type
     /// is represented such that `None` is a null pointer and `Some` is the
     /// identity function.
-    NullablePointer {
+    NicheFilling {
         nndiscr: u64,
         discr: Primitive,
         variants: Vec<CachedLayout>,
@@ -842,8 +826,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
 
 #[derive(PartialEq, Eq, Hash, Debug)]
 pub struct CachedLayout {
-    pub variant_index: Option<usize>,
-    pub layout: Layout,
+    pub variants: Variants,
     pub fields: FieldPlacement,
     pub abi: Abi,
     pub align: Align,
@@ -865,7 +848,7 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 
     tcx.layout_depth.set(depth+1);
-    let layout = Layout::compute_uncached(tcx, param_env, ty);
+    let layout = CachedLayout::compute_uncached(tcx, param_env, ty);
     tcx.layout_depth.set(depth);
 
     layout
@@ -878,18 +861,17 @@ pub fn provide(providers: &mut ty::maps::Providers) {
     };
 }
 
-impl<'a, 'tcx> Layout {
+impl<'a, 'tcx> CachedLayout {
     fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         param_env: ty::ParamEnv<'tcx>,
                         ty: Ty<'tcx>)
-                        -> Result<&'tcx CachedLayout, LayoutError<'tcx>> {
+                        -> Result<&'tcx Self, LayoutError<'tcx>> {
         let cx = (tcx, param_env);
         let dl = cx.data_layout();
         let scalar = |value: Primitive| {
             let align = value.align(dl);
             tcx.intern_layout(CachedLayout {
-                variant_index: None,
-                layout: Layout::Scalar,
+                variants: Variants::Single { index: 0 },
                 fields: FieldPlacement::Union(0),
                 abi: Abi::Scalar(value),
                 size: value.size(dl),
@@ -1028,8 +1010,7 @@ impl<'a, 'tcx> Layout {
             }
 
             Ok(CachedLayout {
-                variant_index: None,
-                layout: Layout::Univariant,
+                variants: Variants::Single { index: 0 },
                 fields: FieldPlacement::Arbitrary {
                     offsets,
                     memory_index
@@ -1073,8 +1054,7 @@ impl<'a, 'tcx> Layout {
                 memory_index: vec![0, 1]
             };
             Ok(tcx.intern_layout(CachedLayout {
-                variant_index: None,
-                layout: Layout::Univariant,
+                variants: Variants::Single { index: 0 },
                 fields,
                 abi: Abi::Aggregate {
                     sized: true,
@@ -1129,8 +1109,7 @@ impl<'a, 'tcx> Layout {
                     .ok_or(LayoutError::SizeOverflow(ty))?;
 
                 tcx.intern_layout(CachedLayout {
-                    variant_index: None,
-                    layout: Layout::Array,
+                    variants: Variants::Single { index: 0 },
                     fields: FieldPlacement::Array {
                         stride: element.size,
                         count
@@ -1147,8 +1126,7 @@ impl<'a, 'tcx> Layout {
             ty::TySlice(element) => {
                 let element = cx.layout_of(element)?;
                 tcx.intern_layout(CachedLayout {
-                    variant_index: None,
-                    layout: Layout::Array,
+                    variants: Variants::Single { index: 0 },
                     fields: FieldPlacement::Array {
                         stride: element.size,
                         count: 0
@@ -1164,8 +1142,7 @@ impl<'a, 'tcx> Layout {
             }
             ty::TyStr => {
                 tcx.intern_layout(CachedLayout {
-                    variant_index: None,
-                    layout: Layout::Array,
+                    variants: Variants::Single { index: 0 },
                     fields: FieldPlacement::Array {
                         stride: Size::from_bytes(1),
                         count: 0
@@ -1238,8 +1215,7 @@ impl<'a, 'tcx> Layout {
                 let size = size.abi_align(align);
 
                 tcx.intern_layout(CachedLayout {
-                    variant_index: None,
-                    layout: Layout::Vector,
+                    variants: Variants::Single { index: 0 },
                     fields: FieldPlacement::Array {
                         stride: element.size,
                         count
@@ -1302,8 +1278,7 @@ impl<'a, 'tcx> Layout {
                     }
 
                     return Ok(tcx.intern_layout(CachedLayout {
-                        variant_index: None,
-                        layout: Layout::UntaggedUnion,
+                        variants: Variants::Single { index: 0 },
                         fields: FieldPlacement::Union(variants[0].len()),
                         abi: Abi::Aggregate {
                             sized: true,
@@ -1332,11 +1307,7 @@ impl<'a, 'tcx> Layout {
                         else { StructKind::AlwaysSized }
                     };
 
-                    let mut cached = univariant_uninterned(&variants[0], &def.repr, kind)?;
-                    if def.is_enum() {
-                        cached.variant_index = Some(0);
-                    }
-                    return Ok(tcx.intern_layout(cached));
+                    return univariant(&variants[0], &def.repr, kind);
                 }
 
                 let no_explicit_discriminants = def.variants.iter().enumerate()
@@ -1359,8 +1330,9 @@ impl<'a, 'tcx> Layout {
                                     univariant_uninterned(&variants[1],
                                         &def.repr, StructKind::AlwaysSized)?
                                 ];
-                                st[0].variant_index = Some(0);
-                                st[1].variant_index = Some(1);
+                                for (i, v) in st.iter_mut().enumerate() {
+                                    v.variants = Variants::Single { index: i };
+                                }
                                 let offset = st[i].fields.offset(field_index) + offset;
                                 let CachedLayout {
                                     mut abi,
@@ -1383,8 +1355,7 @@ impl<'a, 'tcx> Layout {
                                 primitive_align = primitive_align.max(discr_align);
 
                                 return Ok(tcx.intern_layout(CachedLayout {
-                                    variant_index: None,
-                                    layout: Layout::NullablePointer {
+                                    variants: Variants::NicheFilling {
                                         nndiscr: i as u64,
 
                                         discr,
@@ -1426,7 +1397,7 @@ impl<'a, 'tcx> Layout {
                 let mut variants = variants.into_iter().enumerate().map(|(i, field_layouts)| {
                     let mut st = univariant_uninterned(&field_layouts,
                         &def.repr, StructKind::EnumVariant(min_ity))?;
-                    st.variant_index = Some(i);
+                    st.variants = Variants::Single { index: i };
                     // Find the first field we can't move later
                     // to make room for a larger discriminant.
                     for field in st.fields.index_by_increasing_offset().map(|j| field_layouts[j]) {
@@ -1506,8 +1477,7 @@ impl<'a, 'tcx> Layout {
 
                 let discr = Int(ity, signed);
                 tcx.intern_layout(CachedLayout {
-                    variant_index: None,
-                    layout: Layout::General {
+                    variants: Variants::Tagged {
                         discr,
 
                         // FIXME: should be u128?
@@ -1544,7 +1514,7 @@ impl<'a, 'tcx> Layout {
                 return Err(LayoutError::Unknown(ty));
             }
             ty::TyInfer(_) | ty::TyError => {
-                bug!("Layout::compute: unexpected type `{}`", ty)
+                bug!("CachedLayout::compute: unexpected type `{}`", ty)
             }
         })
     }
@@ -1650,8 +1620,8 @@ impl<'a, 'tcx> Layout {
             }
         };
 
-        match layout.layout {
-            Layout::Univariant => {
+        match layout.variants {
+            Variants::Single { .. } => {
                 let variant_names = || {
                     adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::<Vec<_>>()
                 };
@@ -1675,8 +1645,8 @@ impl<'a, 'tcx> Layout {
                 }
             }
 
-            Layout::NullablePointer { .. } |
-            Layout::General { .. } => {
+            Variants::NicheFilling { .. } |
+            Variants::Tagged { .. } => {
                 debug!("print-type-size `{:#?}` adt general variants def {}",
                        ty, adt_def.variants.len());
                 let variant_infos: Vec<_> =
@@ -1688,27 +1658,11 @@ impl<'a, 'tcx> Layout {
                                             layout.for_variant(i))
                     })
                     .collect();
-                record(adt_kind.into(), match layout.layout {
-                    Layout::General { discr, .. } => Some(discr.size(tcx)),
+                record(adt_kind.into(), match layout.variants {
+                    Variants::Tagged { discr, .. } => Some(discr.size(tcx)),
                     _ => None
                 }, variant_infos);
             }
-
-            Layout::UntaggedUnion => {
-                debug!("print-type-size t: `{:?}` adt union", ty);
-                // layout does not currently store info about each
-                // variant...
-                record(adt_kind.into(), None, Vec::new());
-            }
-
-            // other cases provide little interesting (i.e. adjustable
-            // via representation tweaks) size info beyond total size.
-            Layout::Scalar |
-            Layout::Vector |
-            Layout::Array => {
-                debug!("print-type-size t: `{:?}` adt other", ty);
-                record(adt_kind.into(), None, Vec::new())
-            }
         }
     }
 }
@@ -1950,7 +1904,7 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv<'tcx
         // completed, to avoid problems around recursive structures
         // and the like. (Admitedly, I wasn't able to reproduce a problem
         // here, but it seems like the right thing to do. -nmatsakis)
-        Layout::record_layout_for_printing(tcx, ty, param_env, layout);
+        CachedLayout::record_layout_for_printing(tcx, ty, param_env, layout);
 
         Ok(layout)
     }
@@ -1979,7 +1933,7 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>,
         // completed, to avoid problems around recursive structures
         // and the like. (Admitedly, I wasn't able to reproduce a problem
         // here, but it seems like the right thing to do. -nmatsakis)
-        Layout::record_layout_for_printing(tcx_at.tcx, ty, param_env, layout);
+        CachedLayout::record_layout_for_printing(tcx_at.tcx, ty, param_env, layout);
 
         Ok(layout)
     }
@@ -1987,15 +1941,15 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>,
 
 impl<'a, 'tcx> TyLayout<'tcx> {
     pub fn for_variant(&self, variant_index: usize) -> Self {
-        let cached = match self.layout {
-            Layout::NullablePointer { ref variants, .. } |
-            Layout::General { ref variants, .. } => {
+        let cached = match self.variants {
+            Variants::Single { .. } => self.cached,
+
+            Variants::NicheFilling { ref variants, .. } |
+            Variants::Tagged { ref variants, .. } => {
                 &variants[variant_index]
             }
-
-            _ => self.cached
         };
-        assert_eq!(cached.variant_index, Some(variant_index));
+        assert_eq!(cached.variants, Variants::Single { index: variant_index });
 
         TyLayout {
             ty: self.ty,
@@ -2081,26 +2035,17 @@ impl<'a, 'tcx> TyLayout<'tcx> {
 
             // ADTs.
             ty::TyAdt(def, substs) => {
-                let v = if def.is_enum() {
-                    match self.variant_index {
-                        None => match self.layout {
-                            // Discriminant field for enums (where applicable).
-                            Layout::General { discr, .. } |
-                            Layout::NullablePointer { discr, .. } => {
-                                return cx.layout_of([discr.to_ty(tcx)][i]);
-                            }
-                            _ => {
-                                bug!("TyLayout::field_type: enum `{}` has no discriminant",
-                                     self.ty)
-                            }
-                        },
-                        Some(v) => v
+                match self.variants {
+                    Variants::Single { index } => {
+                        def.variants[index].fields[i].ty(tcx, substs)
                     }
-                } else {
-                    0
-                };
 
-                def.variants[v].fields[i].ty(tcx, substs)
+                    // Discriminant field for enums (where applicable).
+                    Variants::Tagged { discr, .. } |
+                    Variants::NicheFilling { discr, .. } => {
+                        return cx.layout_of([discr.to_ty(tcx)][i]);
+                    }
+                }
             }
 
             ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
@@ -2143,18 +2088,18 @@ impl<'a, 'tcx> TyLayout<'tcx> {
                  HasTyCtxt<'tcx>
     {
         let tcx = cx.tcx();
-        match (&self.layout, self.abi, &self.ty.sty) {
+        match (&self.variants, self.abi, &self.ty.sty) {
             // FIXME(eddyb) check this via value ranges on scalars.
-            (&Layout::Scalar, Abi::Scalar(Pointer), &ty::TyRef(..)) |
-            (&Layout::Scalar, Abi::Scalar(Pointer), &ty::TyFnPtr(..)) => {
+            (_, Abi::Scalar(Pointer), &ty::TyRef(..)) |
+            (_, Abi::Scalar(Pointer), &ty::TyFnPtr(..)) => {
                 Ok(Some((Size::from_bytes(0), Pointer)))
             }
-            (&Layout::Scalar, Abi::Scalar(Pointer), &ty::TyAdt(def, _)) if def.is_box() => {
+            (_, Abi::Scalar(Pointer), &ty::TyAdt(def, _)) if def.is_box() => {
                 Ok(Some((Size::from_bytes(0), Pointer)))
             }
 
             // FIXME(eddyb) check this via value ranges on scalars.
-            (&Layout::General { discr, .. }, _, &ty::TyAdt(def, _)) => {
+            (&Variants::Tagged { discr, .. }, _, &ty::TyAdt(def, _)) => {
                 if def.discriminants(tcx).all(|d| d.to_u128_unchecked() != 0) {
                     Ok(Some((self.fields.offset(0), discr)))
                 } else {
@@ -2196,20 +2141,18 @@ impl<'a, 'tcx> TyLayout<'tcx> {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for Layout {
+impl<'gcx> HashStable<StableHashingContext<'gcx>> for Variants {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'gcx>,
                                           hasher: &mut StableHasher<W>) {
-        use ty::layout::Layout::*;
+        use ty::layout::Variants::*;
         mem::discriminant(self).hash_stable(hcx, hasher);
 
         match *self {
-            Scalar => {}
-            Vector => {}
-            Array => {}
-            Univariant => {}
-            UntaggedUnion => {}
-            General {
+            Single { index } => {
+                index.hash_stable(hcx, hasher);
+            }
+            Tagged {
                 discr,
                 discr_range: RangeInclusive { start, end },
                 ref variants,
@@ -2219,7 +2162,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Layout {
                 end.hash_stable(hcx, hasher);
                 variants.hash_stable(hcx, hasher);
             }
-            NullablePointer {
+            NicheFilling {
                 nndiscr,
                 ref variants,
                 ref discr,
@@ -2279,8 +2222,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
 }
 
 impl_stable_hash_for!(struct ::ty::layout::CachedLayout {
-    variant_index,
-    layout,
+    variants,
     fields,
     abi,
     size,
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 761ca662178..46debcce958 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -13,7 +13,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, AdtKind, Ty, TyCtxt};
-use rustc::ty::layout::{Layout, LayoutOf};
+use rustc::ty::layout::{self, LayoutOf};
 use middle::const_val::ConstVal;
 use rustc_const_eval::ConstContext;
 use util::nodemap::FxHashSet;
@@ -753,7 +753,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
                     bug!("failed to get layout for `{}`: {}", t, e)
                 });
 
-                if let Layout::General { ref variants, discr, .. } = layout.layout {
+                if let layout::Variants::Tagged { ref variants, discr, .. } = layout.variants {
                     let discr_size = discr.size(cx.tcx).bytes();
 
                     debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs
index 36ac76aaaa5..d5a51fa1863 100644
--- a/src/librustc_trans/cabi_x86_64.rs
+++ b/src/librustc_trans/cabi_x86_64.rs
@@ -14,7 +14,7 @@
 use abi::{ArgType, ArgAttribute, CastTarget, FnType, LayoutExt, Reg, RegKind};
 use context::CrateContext;
 
-use rustc::ty::layout::{self, Layout, TyLayout, Size};
+use rustc::ty::layout::{self, TyLayout, Size};
 
 #[derive(Clone, Copy, PartialEq, Debug)]
 enum Class {
@@ -87,17 +87,15 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
             }
 
             layout::Abi::Aggregate { .. } => {
-                // FIXME(eddyb) have to work around Rust enums for now.
-                // Fix is either guarantee no data where there is no field,
-                // by putting variants in fields, or be more clever.
-                match layout.layout {
-                    Layout::General { .. } |
-                    Layout::NullablePointer { .. } => return Err(Memory),
-                    _ => {}
-                }
-                for i in 0..layout.fields.count() {
-                    let field_off = off + layout.fields.offset(i);
-                    classify(ccx, layout.field(ccx, i), cls, field_off)?;
+                match layout.variants {
+                    layout::Variants::Single { .. } => {
+                        for i in 0..layout.fields.count() {
+                            let field_off = off + layout.fields.offset(i);
+                            classify(ccx, layout.field(ccx, i), cls, field_off)?;
+                        }
+                    }
+                    layout::Variants::Tagged { .. } |
+                    layout::Variants::NicheFilling { .. } => return Err(Memory),
                 }
             }
 
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 6a7b35c05e7..a905d35f3d3 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -1119,7 +1119,7 @@ fn prepare_union_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 // offset of zero bytes).
 struct EnumMemberDescriptionFactory<'tcx> {
     enum_type: Ty<'tcx>,
-    type_rep: TyLayout<'tcx>,
+    layout: TyLayout<'tcx>,
     discriminant_type_metadata: Option<DIType>,
     containing_scope: DIScope,
     span: Span,
@@ -1129,37 +1129,8 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
     fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
                                       -> Vec<MemberDescription> {
         let adt = &self.enum_type.ty_adt_def().unwrap();
-        match self.type_rep.layout {
-            layout::Layout::General { ref variants, .. } => {
-                let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata
-                    .expect(""));
-                (0..variants.len()).map(|i| {
-                    let variant = self.type_rep.for_variant(i);
-                    let (variant_type_metadata, member_desc_factory) =
-                        describe_enum_variant(cx,
-                                              variant,
-                                              &adt.variants[i],
-                                              discriminant_info,
-                                              self.containing_scope,
-                                              self.span);
-
-                    let member_descriptions = member_desc_factory
-                        .create_member_descriptions(cx);
-
-                    set_members_of_composite_type(cx,
-                                                  variant_type_metadata,
-                                                  &member_descriptions);
-                    MemberDescription {
-                        name: "".to_string(),
-                        type_metadata: variant_type_metadata,
-                        offset: Size::from_bytes(0),
-                        size: variant.size,
-                        align: variant.align,
-                        flags: DIFlags::FlagZero
-                    }
-                }).collect()
-            },
-            layout::Layout::Univariant => {
+        match self.layout.variants {
+            layout::Variants::Single { .. } => {
                 assert!(adt.variants.len() <= 1);
 
                 if adt.variants.is_empty() {
@@ -1167,7 +1138,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
                 } else {
                     let (variant_type_metadata, member_description_factory) =
                         describe_enum_variant(cx,
-                                              self.type_rep,
+                                              self.layout,
                                               &adt.variants[0],
                                               NoDiscriminant,
                                               self.containing_scope,
@@ -1184,19 +1155,48 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
                             name: "".to_string(),
                             type_metadata: variant_type_metadata,
                             offset: Size::from_bytes(0),
-                            size: self.type_rep.size,
-                            align: self.type_rep.align,
+                            size: self.layout.size,
+                            align: self.layout.align,
                             flags: DIFlags::FlagZero
                         }
                     ]
                 }
             }
-            layout::Layout::NullablePointer {
+            layout::Variants::Tagged { ref variants, .. } => {
+                let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata
+                    .expect(""));
+                (0..variants.len()).map(|i| {
+                    let variant = self.layout.for_variant(i);
+                    let (variant_type_metadata, member_desc_factory) =
+                        describe_enum_variant(cx,
+                                              variant,
+                                              &adt.variants[i],
+                                              discriminant_info,
+                                              self.containing_scope,
+                                              self.span);
+
+                    let member_descriptions = member_desc_factory
+                        .create_member_descriptions(cx);
+
+                    set_members_of_composite_type(cx,
+                                                  variant_type_metadata,
+                                                  &member_descriptions);
+                    MemberDescription {
+                        name: "".to_string(),
+                        type_metadata: variant_type_metadata,
+                        offset: Size::from_bytes(0),
+                        size: variant.size,
+                        align: variant.align,
+                        flags: DIFlags::FlagZero
+                    }
+                }).collect()
+            }
+            layout::Variants::NicheFilling {
                 nndiscr,
                 discr,
                 ..
             } => {
-                let variant = self.type_rep.for_variant(nndiscr as usize);
+                let variant = self.layout.for_variant(nndiscr as usize);
                 // Create a description of the non-null variant
                 let (variant_type_metadata, member_description_factory) =
                     describe_enum_variant(cx,
@@ -1237,8 +1237,8 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
                     }
                 }
                 compute_field_path(cx, &mut name,
-                                   self.type_rep,
-                                   self.type_rep.fields.offset(0),
+                                   self.layout,
+                                   self.layout.fields.offset(0),
                                    discr.size(cx));
                 name.push_str(&adt.variants[(1 - nndiscr) as usize].name.as_str());
 
@@ -1253,8 +1253,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
                         flags: DIFlags::FlagZero
                     }
                 ]
-            },
-            ref l @ _ => bug!("Not an enum layout: {:#?}", l)
+            }
         }
     }
 }
@@ -1429,21 +1428,20 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         }
     };
 
-    let type_rep = cx.layout_of(enum_type);
+    let layout = cx.layout_of(enum_type);
 
-    let discriminant_type_metadata = match type_rep.layout {
-        layout::Layout::NullablePointer { .. } |
-        layout::Layout::Univariant { .. } => None,
-        layout::Layout::General { discr, .. } => Some(discriminant_type_metadata(discr)),
-        ref l @ _ => bug!("Not an enum layout: {:#?}", l)
+    let discriminant_type_metadata = match layout.variants {
+        layout::Variants::Single { .. } |
+        layout::Variants::NicheFilling { .. } => None,
+        layout::Variants::Tagged { discr, .. } => Some(discriminant_type_metadata(discr)),
     };
 
-    match (type_rep.abi, discriminant_type_metadata) {
+    match (layout.abi, discriminant_type_metadata) {
         (layout::Abi::Scalar(_), Some(discr)) => return FinalMetadata(discr),
         _ => {}
     }
 
-    let (enum_type_size, enum_type_align) = type_rep.size_and_align();
+    let (enum_type_size, enum_type_align) = layout.size_and_align();
 
     let enum_name = CString::new(enum_name).unwrap();
     let unique_type_id_str = CString::new(
@@ -1471,7 +1469,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         enum_metadata,
         EnumMDF(EnumMemberDescriptionFactory {
             enum_type,
-            type_rep,
+            layout,
             discriminant_type_metadata,
             containing_scope,
             span,
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 45d2f7c69e9..d982fa192b3 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -394,12 +394,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
         },
 
         "discriminant_value" => {
-            match substs.type_at(0).sty {
-                ty::TyAdt(adt, ..) if adt.is_enum() => {
-                    args[0].deref(bcx.ccx).trans_get_discr(bcx, ret_ty)
-                }
-                _ => C_null(llret_ty)
-            }
+            args[0].deref(bcx.ccx).trans_get_discr(bcx, ret_ty)
         }
 
         "align_offset" => {
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 45037a1f198..5a2dcf4fb18 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -1094,8 +1094,26 @@ fn trans_const_adt<'a, 'tcx>(
         mir::AggregateKind::Adt(_, index, _, _) => index,
         _ => 0,
     };
-    match l.layout {
-        layout::Layout::General { .. } => {
+    match l.variants {
+        layout::Variants::Single { index } => {
+            assert_eq!(variant_index, index);
+            if let layout::Abi::Vector { .. } = l.abi {
+                Const::new(C_vector(&vals.iter().map(|x| x.llval).collect::<Vec<_>>()), t)
+            } else if let layout::FieldPlacement::Union(_) = l.fields {
+                assert_eq!(variant_index, 0);
+                assert_eq!(vals.len(), 1);
+                let contents = [
+                    vals[0].llval,
+                    padding(ccx, l.size - ccx.size_of(vals[0].ty))
+                ];
+
+                Const::new(C_struct(ccx, &contents, l.is_packed()), t)
+            } else {
+                assert_eq!(variant_index, 0);
+                build_const_struct(ccx, l, vals, None)
+            }
+        }
+        layout::Variants::Tagged { .. } => {
             let discr = match *kind {
                 mir::AggregateKind::Adt(adt_def, _, _, _) => {
                     adt_def.discriminant_for_variant(ccx.tcx(), variant_index)
@@ -1112,23 +1130,7 @@ fn trans_const_adt<'a, 'tcx>(
                 build_const_struct(ccx, l.for_variant(variant_index), vals, Some(discr))
             }
         }
-        layout::Layout::UntaggedUnion => {
-            assert_eq!(variant_index, 0);
-            let contents = [
-                vals[0].llval,
-                padding(ccx, l.size - ccx.size_of(vals[0].ty))
-            ];
-
-            Const::new(C_struct(ccx, &contents, l.is_packed()), t)
-        }
-        layout::Layout::Univariant => {
-            assert_eq!(variant_index, 0);
-            build_const_struct(ccx, l, vals, None)
-        }
-        layout::Layout::Vector => {
-            Const::new(C_vector(&vals.iter().map(|x| x.llval).collect::<Vec<_>>()), t)
-        }
-        layout::Layout::NullablePointer { nndiscr, .. } => {
+        layout::Variants::NicheFilling { nndiscr, .. } => {
             if variant_index as u64 == nndiscr {
                 build_const_struct(ccx, l.for_variant(variant_index), vals, None)
             } else {
@@ -1137,7 +1139,6 @@ fn trans_const_adt<'a, 'tcx>(
                 Const::new(C_null(ccx.layout_of(t).llvm_type(ccx)), t)
             }
         }
-        _ => bug!("trans_const_adt: cannot handle type {} repreented as {:#?}", t, l)
     }
 }
 
diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs
index f10791cae52..5a558e3652b 100644
--- a/src/librustc_trans/mir/lvalue.rs
+++ b/src/librustc_trans/mir/lvalue.rs
@@ -296,10 +296,13 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
     /// Obtain the actual discriminant of a value.
     pub fn trans_get_discr(self, bcx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef {
         let cast_to = bcx.ccx.layout_of(cast_to).immediate_llvm_type(bcx.ccx);
-        match self.layout.layout {
-            layout::Layout::Univariant { .. } |
-            layout::Layout::UntaggedUnion { .. } => return C_uint(cast_to, 0),
-            _ => {}
+        match self.layout.variants {
+            layout::Variants::Single { index } => {
+                assert_eq!(index, 0);
+                return C_uint(cast_to, 0);
+            }
+            layout::Variants::Tagged { .. } |
+            layout::Variants::NicheFilling { .. } => {},
         }
 
         let discr = self.project_field(bcx, 0);
@@ -307,8 +310,10 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
             layout::Abi::Scalar(discr) => discr,
             _ => bug!("discriminant not scalar: {:#?}", discr.layout)
         };
-        let (min, max) = match self.layout.layout {
-            layout::Layout::General { ref discr_range, .. } => (discr_range.start, discr_range.end),
+        let (min, max) = match self.layout.variants {
+            layout::Variants::Tagged { ref discr_range, .. } => {
+                (discr_range.start, discr_range.end)
+            }
             _ => (0, u64::max_value()),
         };
         let max_next = max.wrapping_add(1);
@@ -333,20 +338,20 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
                 bcx.load(discr.llval, discr.alignment.non_abi())
             }
         };
-        match self.layout.layout {
-            layout::Layout::General { .. } => {
+        match self.layout.variants {
+            layout::Variants::Single { .. } => bug!(),
+            layout::Variants::Tagged { .. } => {
                 let signed = match discr_scalar {
                     layout::Int(_, signed) => signed,
                     _ => false
                 };
                 bcx.intcast(lldiscr, cast_to, signed)
             }
-            layout::Layout::NullablePointer { nndiscr, .. } => {
+            layout::Variants::NicheFilling { nndiscr, .. } => {
                 let cmp = if nndiscr == 0 { llvm::IntEQ } else { llvm::IntNE };
                 let zero = C_null(discr.layout.llvm_type(bcx.ccx));
                 bcx.intcast(bcx.icmp(cmp, lldiscr, zero), cast_to, false)
             }
-            _ => bug!("{} is not an enum", self.layout.ty)
         }
     }
 
@@ -356,13 +361,17 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
         let to = self.layout.ty.ty_adt_def().unwrap()
             .discriminant_for_variant(bcx.tcx(), variant_index)
             .to_u128_unchecked() as u64;
-        match self.layout.layout {
-            layout::Layout::General { .. } => {
+        match self.layout.variants {
+            layout::Variants::Single { index } => {
+                assert_eq!(to, 0);
+                assert_eq!(variant_index, index);
+            }
+            layout::Variants::Tagged { .. } => {
                 let ptr = self.project_field(bcx, 0);
                 bcx.store(C_int(ptr.layout.llvm_type(bcx.ccx), to as i64),
                     ptr.llval, ptr.alignment.non_abi());
             }
-            layout::Layout::NullablePointer { nndiscr, .. } => {
+            layout::Variants::NicheFilling { nndiscr, .. } => {
                 if to != nndiscr {
                     let use_memset = match self.layout.abi {
                         layout::Abi::Scalar(_) => false,
@@ -385,9 +394,6 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
                     }
                 }
             }
-            _ => {
-                assert_eq!(to, 0);
-            }
         }
     }
 
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 0d183115211..d3677e2eefd 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -11,7 +11,7 @@
 use llvm::{self, ValueRef};
 use rustc::ty::{self, Ty};
 use rustc::ty::cast::{CastTy, IntTy};
-use rustc::ty::layout::{self, Layout, LayoutOf};
+use rustc::ty::layout::{self, LayoutOf};
 use rustc::mir;
 use rustc::middle::lang_items::ExchangeMallocFnLangItem;
 use rustc_apfloat::{ieee, Float, Status, Round};
@@ -278,8 +278,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                         let ll_t_out = cast.immediate_llvm_type(bcx.ccx);
                         let llval = operand.immediate();
 
-                        if let Layout::General { ref discr_range, .. } = operand.layout.layout {
-                            if discr_range.end > discr_range.start {
+                        match operand.layout.variants {
+                            layout::Variants::Tagged {
+                                ref discr_range, ..
+                            } if discr_range.end > discr_range.start => {
                                 // We want `table[e as usize]` to not
                                 // have bound checks, and this is the most
                                 // convenient place to put the `assume`.
@@ -290,6 +292,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                                     C_uint(ll_t_in, discr_range.end)
                                 ));
                             }
+                            _ => {}
                         }
 
                         let signed = match operand.layout.abi {
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 52151035a82..2b3ac0386ee 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -40,8 +40,13 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             let mut name = String::with_capacity(32);
             let printer = DefPathBasedNames::new(ccx.tcx(), true, true);
             printer.push_type_name(layout.ty, &mut name);
-            if let (&ty::TyAdt(def, _), Some(v)) = (&layout.ty.sty, layout.variant_index) {
-                write!(&mut name, "::{}", def.variants[v].name).unwrap();
+            match (&layout.ty.sty, &layout.variants) {
+                (&ty::TyAdt(def, _), &layout::Variants::Single { index }) => {
+                    if def.is_enum() && !def.variants.is_empty() {
+                        write!(&mut name, "::{}", def.variants[index].name).unwrap();
+                    }
+                }
+                _ => {}
             }
             Some(name)
         }
@@ -206,7 +211,11 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
 
 
         // Check the cache.
-        if let Some(&llty) = ccx.lltypes().borrow().get(&(self.ty, self.variant_index)) {
+        let variant_index = match self.variants {
+            layout::Variants::Single { index } => Some(index),
+            _ => None
+        };
+        if let Some(&llty) = ccx.lltypes().borrow().get(&(self.ty, variant_index)) {
             return llty;
         }
 
@@ -221,7 +230,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
         let mut defer = None;
         let llty = if self.ty != normal_ty {
             let mut layout = ccx.layout_of(normal_ty);
-            if let Some(v) = self.variant_index {
+            if let Some(v) = variant_index {
                 layout = layout.for_variant(v);
             }
             layout.llvm_type(ccx)
@@ -230,7 +239,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
         };
         debug!("--> mapped {:#?} to llty={:?}", self, llty);
 
-        ccx.lltypes().borrow_mut().insert((self.ty, self.variant_index), llty);
+        ccx.lltypes().borrow_mut().insert((self.ty, variant_index), llty);
 
         if let Some((mut llty, layout)) = defer {
             llty.set_struct_body(&struct_llfields(ccx, layout), layout.is_packed())