rustc: hide details in Layout in favor of Abi or FieldPlacement.
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 096c74a..13d3ec6 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -627,27 +627,27 @@
 #[derive(PartialEq, Eq, Hash, Debug)]
 pub struct Struct {
     /// Maximum alignment of fields and repr alignment.
-    pub align: Align,
+    align: Align,
 
     /// Primitive alignment of fields without repr alignment.
-    pub primitive_align: Align,
+    primitive_align: Align,
 
     /// If true, no alignment padding is used.
-    pub packed: bool,
+    packed: bool,
 
     /// If true, the size is exact, otherwise it's only a lower bound.
-    pub sized: bool,
+    sized: bool,
 
     /// Offsets for the first byte of each field, ordered to match the source definition order.
     /// This vector does not go in increasing order.
     /// FIXME(eddyb) use small vector optimization for the common case.
-    pub offsets: Vec<Size>,
+    offsets: Vec<Size>,
 
     /// Maps source order field indices to memory order indices, depending how fields were permuted.
     /// FIXME (camlorn) also consider small vector  optimization here.
     pub memory_index: Vec<u32>,
 
-    pub min_size: Size,
+    min_size: Size,
 }
 
 /// Info required to optimize struct layout.
@@ -799,7 +799,7 @@
     }
 
     /// Get the size with trailing alignment padding.
-    pub fn stride(&self) -> Size {
+    fn stride(&self) -> Size {
         self.min_size.abi_align(self.align)
     }
 
@@ -837,11 +837,11 @@
                               layout: FullLayout<'tcx>)
                               -> Result<Option<(Size, Primitive)>, LayoutError<'tcx>> {
         let cx = (tcx, param_env);
-        match (layout.layout, &layout.ty.sty) {
-            (&Scalar(Pointer), _) if !layout.ty.is_unsafe_ptr() => {
+        match (layout.layout, layout.abi, &layout.ty.sty) {
+            (&Scalar, Abi::Scalar(Pointer), _) if !layout.ty.is_unsafe_ptr() => {
                 Ok(Some((Size::from_bytes(0), Pointer)))
             }
-            (&General { discr, .. }, &ty::TyAdt(def, _)) => {
+            (&General { discr, .. }, _, &ty::TyAdt(def, _)) => {
                 if def.discriminants(tcx).all(|d| d.to_u128_unchecked() != 0) {
                     Ok(Some((layout.fields.offset(0), discr)))
                 } else {
@@ -849,18 +849,18 @@
                 }
             }
 
-            (&FatPointer(_), _) if !layout.ty.is_unsafe_ptr() => {
+            (&FatPointer, _, _) if !layout.ty.is_unsafe_ptr() => {
                 Ok(Some((layout.fields.offset(FAT_PTR_ADDR), Pointer)))
             }
 
             // Is this the NonZero lang item wrapping a pointer or integer type?
-            (_, &ty::TyAdt(def, _)) if Some(def.did) == tcx.lang_items().non_zero() => {
+            (_, _, &ty::TyAdt(def, _)) if Some(def.did) == tcx.lang_items().non_zero() => {
                 let field = layout.field(cx, 0)?;
-                match *field.layout {
-                    Scalar(value) => {
+                match (field.layout, field.abi) {
+                    (&Scalar, Abi::Scalar(value)) => {
                         Ok(Some((layout.fields.offset(0), value)))
                     }
-                    FatPointer(_) => {
+                    (&FatPointer, _) => {
                         Ok(Some((layout.fields.offset(0) +
                                  field.fields.offset(FAT_PTR_ADDR),
                                  Pointer)))
@@ -870,7 +870,7 @@
             }
 
             // Perhaps one of the fields is non-zero, let's recurse and find out.
-            (&Univariant(ref variant), _) => {
+            (&Univariant(ref variant), _, _) => {
                 variant.non_zero_field(
                     tcx,
                     param_env,
@@ -879,7 +879,7 @@
 
             // Is this a fixed-size array of something non-zero
             // with at least one element?
-            (_, &ty::TyArray(ety, mut count)) => {
+            (_, _, &ty::TyArray(ety, mut count)) => {
                 if count.has_projections() {
                     count = tcx.normalize_associated_type_in_env(&count, param_env);
                     if count.has_projections() {
@@ -893,7 +893,7 @@
                 }
             }
 
-            (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
+            (_, _, &ty::TyProjection(_)) | (_, _, &ty::TyAnon(..)) => {
                 bug!("Struct::non_zero_field_in_type: {:?} not normalized", layout);
             }
 
@@ -920,79 +920,6 @@
     }
 }
 
-/// An untagged union.
-#[derive(PartialEq, Eq, Hash, Debug)]
-pub struct Union {
-    pub align: Align,
-    pub primitive_align: Align,
-
-    pub min_size: Size,
-
-    /// If true, no alignment padding is used.
-    pub packed: bool,
-}
-
-impl<'a, 'tcx> Union {
-    fn new(dl: &TargetDataLayout, repr: &ReprOptions) -> Union {
-        if repr.packed() && repr.align > 0 {
-            bug!("Union cannot be packed and aligned");
-        }
-
-        let primitive_align = if repr.packed() {
-            dl.i8_align
-        } else {
-            dl.aggregate_align
-        };
-
-        let align = if repr.align > 0 {
-            let repr_align = repr.align as u64;
-            debug!("Union::new repr_align: {:?}", repr_align);
-            primitive_align.max(Align::from_bytes(repr_align, repr_align).unwrap())
-        } else {
-            primitive_align
-        };
-
-        Union {
-            align,
-            primitive_align,
-            min_size: Size::from_bytes(0),
-            packed: repr.packed(),
-        }
-    }
-
-    /// Extend the Union with more fields.
-    fn extend<I>(&mut self, dl: &TargetDataLayout,
-                 fields: I,
-                 scapegoat: Ty<'tcx>)
-                 -> Result<(), LayoutError<'tcx>>
-    where I: Iterator<Item=Result<FullLayout<'a>, LayoutError<'tcx>>> {
-        for (index, field) in fields.enumerate() {
-            let field = field?;
-            if field.is_unsized() {
-                bug!("Union::extend: field #{} of `{}` is unsized",
-                     index, scapegoat);
-            }
-
-            debug!("Union::extend field: {:?} {:?}", field, field.size(dl));
-
-            if !self.packed {
-                self.align = self.align.max(field.align(dl));
-                self.primitive_align = self.primitive_align.max(field.primitive_align(dl));
-            }
-            self.min_size = cmp::max(self.min_size, field.size(dl));
-        }
-
-        debug!("Union::extend min-size: {:?}", self.min_size);
-
-        Ok(())
-    }
-
-    /// Get the size with trailing alignment padding.
-    pub fn stride(&self) -> Size {
-        self.min_size.abi_align(self.align)
-    }
-}
-
 /// The first half of a fat pointer.
 /// - For a trait object, this is the address of the box.
 /// - For a slice, this is the base address.
@@ -1068,6 +995,7 @@
     Aggregate {
         /// If true, the size is exact, otherwise it's only a lower bound.
         sized: bool,
+        packed: bool,
         align: Align,
         primitive_align: Align,
         size: Size
@@ -1078,11 +1006,19 @@
     /// Returns true if the layout corresponds to an unsized type.
     pub fn is_unsized(&self) -> bool {
         match *self {
-            Abi::Scalar(_) | Abi::Vector {..} => false,
+            Abi::Scalar(_) | Abi::Vector { .. } => false,
             Abi::Aggregate { sized, .. } => !sized
         }
     }
 
+    /// Returns true if the fields of the layout are packed.
+    pub fn is_packed(&self) -> bool {
+        match *self {
+            Abi::Scalar(_) | Abi::Vector { .. } => false,
+            Abi::Aggregate { packed, .. } => packed
+        }
+    }
+
     pub fn size<C: HasDataLayout>(&self, cx: C) -> Size {
         let dl = cx.data_layout();
 
@@ -1144,26 +1080,16 @@
 #[derive(PartialEq, Eq, Hash, Debug)]
 pub enum Layout<'a> {
     /// TyBool, TyChar, TyInt, TyUint, TyFloat, TyRawPtr, TyRef or TyFnPtr.
-    Scalar(Primitive),
+    Scalar,
 
     /// SIMD vectors, from structs marked with #[repr(simd)].
-    Vector {
-        element: Primitive,
-        count: u64
-    },
+    Vector,
 
     /// TyArray, TySlice or TyStr.
-    Array {
-        /// If true, the size is exact, otherwise it's only a lower bound.
-        sized: bool,
-        align: Align,
-        primitive_align: Align,
-        element_size: Size,
-        count: u64
-    },
+    Array,
 
     /// TyRawPtr or TyRef with a !Sized pointee. The primitive is the metadata.
-    FatPointer(Primitive),
+    FatPointer,
 
     // Remaining variants are all ADTs such as structs, enums or tuples.
 
@@ -1171,7 +1097,7 @@
     Univariant(Struct),
 
     /// Untagged unions.
-    UntaggedUnion(Union),
+    UntaggedUnion,
 
     /// 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
@@ -1185,9 +1111,6 @@
         // taking everything else as the (shortest) discriminant range.
         discr_range: RangeInclusive<u64>,
         variants: Vec<CachedLayout<'a>>,
-        size: Size,
-        align: Align,
-        primitive_align: Align,
     },
 
     /// Two cases distinguished by a nullable pointer: the case with discriminant
@@ -1203,9 +1126,6 @@
         discr: Primitive,
         discr_offset: Size,
         variants: Vec<CachedLayout<'a>>,
-        size: Size,
-        align: Align,
-        primitive_align: Align,
     }
 }
 
@@ -1269,159 +1189,98 @@
                         -> Result<CachedLayout<'tcx>, LayoutError<'tcx>> {
         let cx = (tcx, param_env);
         let dl = cx.data_layout();
-        let success = |layout| {
-            let layout = tcx.intern_layout(layout);
+        let scalar = |value| {
+            CachedLayout {
+                layout: &Layout::Scalar,
+                fields: FieldPlacement::union(0),
+                abi: Abi::Scalar(value)
+            }
+        };
+        let univariant = |st| {
+            let layout = tcx.intern_layout(Layout::Univariant(st));
             let fields = match *layout {
-                Scalar(_) => {
-                    FieldPlacement::union(0)
-                }
-
-                Vector { element, count } => {
-                    FieldPlacement::Linear {
-                        stride: element.size(tcx),
-                        count
-                    }
-                }
-
-                Array { element_size, count, .. } => {
-                    FieldPlacement::Linear {
-                        stride: element_size,
-                        count
-                    }
-                }
-
-                FatPointer { .. } => {
-                    FieldPlacement::Linear {
-                        stride: Pointer.size(tcx),
-                        count: 2
-                    }
-                }
-
                 Univariant(ref variant) => {
                     FieldPlacement::Arbitrary {
                         offsets: &variant.offsets
                     }
                 }
-
-                UntaggedUnion(_) => {
-                    // Handle unions through the type rather than Layout.
-                    let def = ty.ty_adt_def().unwrap();
-                    FieldPlacement::union(def.struct_variant().fields.len())
-                }
-
-                General { .. } => FieldPlacement::union(1),
-
-                NullablePointer { ref discr_offset, .. } => {
-                    FieldPlacement::Arbitrary {
-                        offsets: ref_slice(discr_offset)
-                    }
-                }
+                _ => bug!()
             };
             let abi = match *layout {
-                Scalar(value) => Abi::Scalar(value),
-                Vector { element, count } => Abi::Vector { element, count },
-
-                Array { sized, align, primitive_align, element_size, count, .. } => {
-                    let size = match element_size.checked_mul(count, dl) {
-                        Some(size) => size,
-                        None => return Err(LayoutError::SizeOverflow(ty))
-                    };
-                    Abi::Aggregate {
-                        sized,
-                        align,
-                        primitive_align,
-                        size
-                    }
-                }
-
-                FatPointer(metadata) => {
-                    // Effectively a (ptr, meta) tuple.
-                    let align = Pointer.align(dl).max(metadata.align(dl));
-                    Abi::Aggregate {
-                        sized: true,
-                        align,
-                        primitive_align: align,
-                        size: (Pointer.size(dl).abi_align(metadata.align(dl)) +
-                               metadata.size(dl))
-                            .abi_align(align)
-                    }
-                }
-
                 Univariant(ref st) => {
                     Abi::Aggregate {
                         sized: st.sized,
+                        packed: st.packed,
                         align: st.align,
                         primitive_align: st.primitive_align,
                         size: st.stride()
                     }
                 }
-
-                UntaggedUnion(ref un ) => {
-                    Abi::Aggregate {
-                        sized: true,
-                        align: un.align,
-                        primitive_align: un.primitive_align,
-                        size: un.stride()
-                    }
-                }
-
-                General { discr, align, primitive_align, size, .. } |
-                NullablePointer { discr, align, primitive_align, size, .. } => {
-                    if fields.offset(0).bytes() == 0 && discr.size(cx) == size {
-                        Abi::Scalar(discr)
-                    } else {
-                        Abi::Aggregate {
-                            sized: true,
-                            align,
-                            primitive_align,
-                            size
-                        }
-                    }
-                }
+                _ => bug!()
             };
-            Ok(CachedLayout {
+            CachedLayout {
                 layout,
                 fields,
                 abi
-            })
+            }
         };
         assert!(!ty.has_infer_types());
 
         let ptr_layout = |pointee: Ty<'tcx>| {
             let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env);
             if pointee.is_sized(tcx, param_env, DUMMY_SP) {
-                Ok(Scalar(Pointer))
-            } else {
-                let unsized_part = tcx.struct_tail(pointee);
-                let metadata = match unsized_part.sty {
-                    ty::TyForeign(..) => return Ok(Scalar(Pointer)),
-                    ty::TySlice(_) | ty::TyStr => {
-                        Int(dl.ptr_sized_integer(), false)
-                    }
-                    ty::TyDynamic(..) => Pointer,
-                    _ => return Err(LayoutError::Unknown(unsized_part))
-                };
-                Ok(FatPointer(metadata))
+                return Ok(scalar(Pointer));
             }
+
+            let unsized_part = tcx.struct_tail(pointee);
+            let metadata = match unsized_part.sty {
+                ty::TyForeign(..) => return Ok(scalar(Pointer)),
+                ty::TySlice(_) | ty::TyStr => {
+                    Int(dl.ptr_sized_integer(), false)
+                }
+                ty::TyDynamic(..) => Pointer,
+                _ => return Err(LayoutError::Unknown(unsized_part))
+            };
+
+            // Effectively a (ptr, meta) tuple.
+            let align = Pointer.align(dl).max(metadata.align(dl));
+            let fields = FieldPlacement::Linear {
+                stride: Pointer.size(dl),
+                count: 2
+            };
+            let meta_offset = fields.offset(1);
+            assert_eq!(meta_offset, meta_offset.abi_align(metadata.align(dl)));
+            Ok(CachedLayout {
+                layout: tcx.intern_layout(Layout::FatPointer),
+                fields,
+                abi:
+                Abi::Aggregate {
+                    sized: true,
+                    packed: false,
+                    align,
+                    primitive_align: align,
+                    size: (meta_offset + metadata.size(dl)).abi_align(align)
+                }
+            })
         };
 
-        let layout = match ty.sty {
+        Ok(match ty.sty {
             // Basic scalars.
-            ty::TyBool => Scalar(Int(I1, false)),
-            ty::TyChar => Scalar(Int(I32, false)),
+            ty::TyBool => scalar(Int(I1, false)),
+            ty::TyChar => scalar(Int(I32, false)),
             ty::TyInt(ity) => {
-                Scalar(Int(Integer::from_attr(dl, attr::SignedInt(ity)), true))
+                scalar(Int(Integer::from_attr(dl, attr::SignedInt(ity)), true))
             }
             ty::TyUint(ity) => {
-                Scalar(Int(Integer::from_attr(dl, attr::UnsignedInt(ity)), false))
+                scalar(Int(Integer::from_attr(dl, attr::UnsignedInt(ity)), false))
             }
-            ty::TyFloat(FloatTy::F32) => Scalar(F32),
-            ty::TyFloat(FloatTy::F64) => Scalar(F64),
-            ty::TyFnPtr(_) => Scalar(Pointer),
+            ty::TyFloat(FloatTy::F32) => scalar(F32),
+            ty::TyFloat(FloatTy::F64) => scalar(F64),
+            ty::TyFnPtr(_) => scalar(Pointer),
 
             // The never type.
             ty::TyNever => {
-                Univariant(Struct::new(dl, &[], &ReprOptions::default(),
+                univariant(Struct::new(dl, &[], &ReprOptions::default(),
                                        StructKind::AlwaysSizedUnivariant, ty)?)
             }
 
@@ -1446,50 +1305,74 @@
                 let element = cx.layout_of(element)?;
                 let element_size = element.size(dl);
                 let count = count.val.to_const_int().unwrap().to_u64().unwrap();
-                Array {
-                    sized: true,
-                    align: element.align(dl),
-                    primitive_align: element.primitive_align(dl),
-                    element_size,
-                    count,
+                let size = element_size.checked_mul(count, dl)
+                    .ok_or(LayoutError::SizeOverflow(ty))?;
+
+                CachedLayout {
+                    layout: &Layout::Array,
+                    fields: FieldPlacement::Linear {
+                        stride: element_size,
+                        count
+                    },
+                    abi: Abi::Aggregate {
+                        sized: true,
+                        packed: false,
+                        align: element.align(dl),
+                        primitive_align: element.primitive_align(dl),
+                        size
+                    }
                 }
             }
             ty::TySlice(element) => {
                 let element = cx.layout_of(element)?;
-                Array {
-                    sized: false,
-                    align: element.align(dl),
-                    primitive_align: element.primitive_align(dl),
-                    element_size: element.size(dl),
-                    count: 0
+                CachedLayout {
+                    layout: &Layout::Array,
+                    fields: FieldPlacement::Linear {
+                        stride: element.size(dl),
+                        count: 0
+                    },
+                    abi: Abi::Aggregate {
+                        sized: false,
+                        packed: false,
+                        align: element.align(dl),
+                        primitive_align: element.primitive_align(dl),
+                        size: Size::from_bytes(0)
+                    }
                 }
             }
             ty::TyStr => {
-                Array {
-                    sized: false,
-                    align: dl.i8_align,
-                    primitive_align: dl.i8_align,
-                    element_size: Size::from_bytes(1),
-                    count: 0
+                CachedLayout {
+                    layout: &Layout::Array,
+                    fields: FieldPlacement::Linear {
+                        stride: Size::from_bytes(1),
+                        count: 0
+                    },
+                    abi: Abi::Aggregate {
+                        sized: false,
+                        packed: false,
+                        align: dl.i8_align,
+                        primitive_align: dl.i8_align,
+                        size: Size::from_bytes(0)
+                    }
                 }
             }
 
             // Odd unit types.
             ty::TyFnDef(..) => {
-                Univariant(Struct::new(dl, &[], &ReprOptions::default(),
+                univariant(Struct::new(dl, &[], &ReprOptions::default(),
                                        StructKind::AlwaysSizedUnivariant, ty)?)
             }
             ty::TyDynamic(..) | ty::TyForeign(..) => {
                 let mut unit = Struct::new(dl, &[], &ReprOptions::default(),
                   StructKind::AlwaysSizedUnivariant, ty)?;
                 unit.sized = false;
-                Univariant(unit)
+                univariant(unit)
             }
 
             // Tuples, generators and closures.
             ty::TyGenerator(def_id, ref substs, _) => {
                 let tys = substs.field_tys(def_id, tcx);
-                Univariant(Struct::new(dl,
+                univariant(Struct::new(dl,
                     &tys.map(|ty| cx.layout_of(ty))
                       .collect::<Result<Vec<_>, _>>()?,
                     &ReprOptions::default(),
@@ -1498,7 +1381,7 @@
 
             ty::TyClosure(def_id, ref substs) => {
                 let tys = substs.upvar_tys(def_id, tcx);
-                Univariant(Struct::new(dl,
+                univariant(Struct::new(dl,
                     &tys.map(|ty| cx.layout_of(ty))
                       .collect::<Result<Vec<_>, _>>()?,
                     &ReprOptions::default(),
@@ -1512,7 +1395,7 @@
                     StructKind::MaybeUnsizedUnivariant
                 };
 
-                Univariant(Struct::new(dl,
+                univariant(Struct::new(dl,
                     &tys.iter().map(|ty| cx.layout_of(ty))
                       .collect::<Result<Vec<_>, _>>()?,
                     &ReprOptions::default(), kind, ty)?)
@@ -1520,19 +1403,23 @@
 
             // SIMD vector types.
             ty::TyAdt(def, ..) if def.repr.simd() => {
+                let count = ty.simd_size(tcx) as u64;
                 let element = ty.simd_type(tcx);
-                match cx.layout_of(element)?.abi {
-                    Abi::Scalar(value) => {
-                        return success(Vector {
-                            element: value,
-                            count: ty.simd_size(tcx) as u64
-                        });
-                    }
+                let element = match cx.layout_of(element)?.abi {
+                    Abi::Scalar(value) => value,
                     _ => {
                         tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \
                                                 a non-machine element type `{}`",
                                                 ty, element));
                     }
+                };
+                CachedLayout {
+                    layout: &Layout::Vector,
+                    fields: FieldPlacement::Linear {
+                        stride: element.size(tcx),
+                        count
+                    },
+                    abi: Abi::Vector { element, count }
                 }
             }
 
@@ -1549,10 +1436,54 @@
                     // Uninhabitable; represent as unit
                     // (Typechecking will reject discriminant-sizing attrs.)
 
-                    return success(Univariant(Struct::new(dl, &[],
+                    return Ok(univariant(Struct::new(dl, &[],
                           &def.repr, StructKind::AlwaysSizedUnivariant, ty)?));
                 }
 
+                if def.is_union() {
+                    let packed = def.repr.packed();
+                    if packed && def.repr.align > 0 {
+                        bug!("Union cannot be packed and aligned");
+                    }
+
+                    let mut primitive_align = if def.repr.packed() {
+                        dl.i8_align
+                    } else {
+                        dl.aggregate_align
+                    };
+
+                    let mut align = if def.repr.align > 0 {
+                        let repr_align = def.repr.align as u64;
+                        primitive_align.max(
+                            Align::from_bytes(repr_align, repr_align).unwrap())
+                    } else {
+                        primitive_align
+                    };
+
+                    let mut size = Size::from_bytes(0);
+                    for field in &variants[0] {
+                        assert!(!field.is_unsized());
+
+                        if !packed {
+                            align = align.max(field.align(dl));
+                            primitive_align = primitive_align.max(field.primitive_align(dl));
+                        }
+                        size = cmp::max(size, field.size(dl));
+                    }
+
+                    return Ok(CachedLayout {
+                        layout: &Layout::UntaggedUnion,
+                        fields: FieldPlacement::union(variants[0].len()),
+                        abi: Abi::Aggregate {
+                            sized: true,
+                            packed,
+                            align,
+                            primitive_align,
+                            size: size.abi_align(align)
+                        }
+                    });
+                }
+
                 if !def.is_enum() || (variants.len() == 1 &&
                                       !def.repr.inhibit_enum_layout_opt() &&
                                       !variants[0].is_empty()) {
@@ -1570,14 +1501,7 @@
                         else { StructKind::AlwaysSizedUnivariant }
                     };
 
-                    let layout = if def.is_union() {
-                        let mut un = Union::new(dl, &def.repr);
-                        un.extend(dl, variants[0].iter().map(|&f| Ok(f)), ty)?;
-                        UntaggedUnion(un)
-                    } else {
-                        Univariant(Struct::new(dl, &variants[0], &def.repr, kind, ty)?)
-                    };
-                    return success(layout);
+                    return Ok(univariant(Struct::new(dl, &variants[0], &def.repr, kind, ty)?));
                 }
 
                 let no_explicit_discriminants = def.variants.iter().enumerate()
@@ -1608,25 +1532,49 @@
                         }
                     }
 
-                    if let Some((discr, offset, primitive)) = choice {
-                        let mut discr_align = primitive.align(dl);
-                        if offset.abi_align(discr_align) != offset {
-                            st[discr].packed = true;
-                            discr_align = dl.i8_align;
-                        }
-                        let align = st[discr].align.max(discr_align);
-                        let primitive_align = st[discr].primitive_align.max(discr_align);
+                    if let Some((nndiscr, offset, discr)) = choice {
+                        let variants: Vec<_> = st.into_iter().map(&univariant).collect();
+                        let mut abi = variants[nndiscr].abi;
 
-                        return success(NullablePointer {
-                            nndiscr: discr as u64,
-                            discr: primitive,
+                        let mut discr_align = discr.align(dl);
+                        match abi {
+                            Abi::Aggregate {
+                                ref mut align,
+                                ref mut primitive_align,
+                                ref mut packed,
+                                ..
+                            } => {
+                                if offset.abi_align(discr_align) != offset {
+                                    *packed = true;
+                                    discr_align = dl.i8_align;
+                                }
+                                *align = align.max(discr_align);
+                                *primitive_align = primitive_align.max(discr_align);
+                            }
+                            _ => {}
+                        }
+
+                        let layout = tcx.intern_layout(Layout::NullablePointer {
+                            nndiscr: nndiscr as u64,
+                            discr,
                             discr_offset: offset,
-                            size: st[discr].stride(),
-                            align,
-                            primitive_align,
-                            variants: st.into_iter().map(|variant| {
-                                success(Univariant(variant))
-                            }).collect::<Result<Vec<_>, _>>()?,
+                            variants,
+                        });
+                        return Ok(CachedLayout {
+                            layout,
+                            fields: match *layout {
+                                Layout::NullablePointer { ref discr_offset, .. } => {
+                                    FieldPlacement::Arbitrary {
+                                        offsets: ref_slice(discr_offset)
+                                    }
+                                }
+                                _ => bug!()
+                            },
+                            abi: if offset.bytes() == 0 && discr.size(dl) == abi.size(dl) {
+                                Abi::Scalar(discr)
+                            } else {
+                                abi
+                            }
                         });
                     }
                 }
@@ -1727,17 +1675,27 @@
                     }
                 }
 
-                General {
-                    discr: Int(ity, signed),
+                let discr = Int(ity, signed);
+                CachedLayout {
+                    layout: tcx.intern_layout(Layout::General {
+                        discr,
 
-                    // FIXME: should be u128?
-                    discr_range: (min as u64)..=(max as u64),
-                    variants: variants.into_iter().map(|variant| {
-                        success(Univariant(variant))
-                    }).collect::<Result<Vec<_>, _>>()?,
-                    size,
-                    align,
-                    primitive_align,
+                        // FIXME: should be u128?
+                        discr_range: (min as u64)..=(max as u64),
+                        variants: variants.into_iter().map(&univariant).collect(),
+                    }),
+                    fields: FieldPlacement::union(1),
+                    abi: if discr.size(dl) == size {
+                        Abi::Scalar(discr)
+                    } else {
+                        Abi::Aggregate {
+                            sized: true,
+                            packed: false,
+                            align,
+                            primitive_align,
+                            size
+                        }
+                    }
                 }
             }
 
@@ -1748,11 +1706,11 @@
                     return Err(LayoutError::Unknown(ty));
                 }
                 let layout = cx.layout_of(normalized)?;
-                return Ok(CachedLayout {
+                CachedLayout {
                     layout: layout.layout,
                     fields: layout.fields,
                     abi: layout.abi
-                });
+                }
             }
             ty::TyParam(_) => {
                 return Err(LayoutError::Unknown(ty));
@@ -1760,9 +1718,7 @@
             ty::TyInfer(_) | ty::TyError => {
                 bug!("Layout::compute: unexpected type `{}`", ty)
             }
-        };
-
-        success(layout)
+        })
     }
 
     /// This is invoked by the `layout_raw` query to record the final
@@ -1916,8 +1872,8 @@
                 }, variant_infos);
             }
 
-            Layout::UntaggedUnion(ref un) => {
-                debug!("print-type-size t: `{:?}` adt union {:?}", ty, un);
+            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());
@@ -1925,9 +1881,9 @@
 
             // other cases provide little interesting (i.e. adjustable
             // via representation tweaks) size info beyond total size.
-            Layout::Scalar(_) |
-            Layout::Vector { .. } |
-            Layout::Array { .. } |
+            Layout::Scalar |
+            Layout::Vector |
+            Layout::Array |
             Layout::FatPointer { .. } => {
                 debug!("print-type-size t: `{:?}` adt other", ty);
                 record(adt_kind.into(), None, Vec::new())
@@ -2333,6 +2289,11 @@
         self.abi.is_unsized()
     }
 
+    /// Returns true if the fields of the layout are packed.
+    pub fn is_packed(&self) -> bool {
+        self.abi.is_packed()
+    }
+
     pub fn size<C: HasDataLayout>(&self, cx: C) -> Size {
         self.abi.size(cx)
     }
@@ -2359,61 +2320,34 @@
         mem::discriminant(self).hash_stable(hcx, hasher);
 
         match *self {
-            Scalar(ref value) => {
-                value.hash_stable(hcx, hasher);
-            }
-            Vector { element, count } => {
-                element.hash_stable(hcx, hasher);
-                count.hash_stable(hcx, hasher);
-            }
-            Array { sized, align, primitive_align, element_size, count } => {
-                sized.hash_stable(hcx, hasher);
-                align.hash_stable(hcx, hasher);
-                primitive_align.hash_stable(hcx, hasher);
-                element_size.hash_stable(hcx, hasher);
-                count.hash_stable(hcx, hasher);
-            }
-            FatPointer(ref metadata) => {
-                metadata.hash_stable(hcx, hasher);
-            }
+            Scalar => {}
+            Vector => {}
+            Array => {}
+            FatPointer => {}
             Univariant(ref variant) => {
                 variant.hash_stable(hcx, hasher);
             }
-            UntaggedUnion(ref un) => {
-                un.hash_stable(hcx, hasher);
-            }
+            UntaggedUnion => {}
             General {
                 discr,
                 discr_range: RangeInclusive { start, end },
                 ref variants,
-                size,
-                align,
-                primitive_align
             } => {
                 discr.hash_stable(hcx, hasher);
                 start.hash_stable(hcx, hasher);
                 end.hash_stable(hcx, hasher);
                 variants.hash_stable(hcx, hasher);
-                size.hash_stable(hcx, hasher);
-                align.hash_stable(hcx, hasher);
-                primitive_align.hash_stable(hcx, hasher);
             }
             NullablePointer {
                 nndiscr,
                 ref variants,
                 ref discr,
                 discr_offset,
-                size,
-                align,
-                primitive_align
             } => {
                 nndiscr.hash_stable(hcx, hasher);
                 variants.hash_stable(hcx, hasher);
                 discr.hash_stable(hcx, hasher);
                 discr_offset.hash_stable(hcx, hasher);
-                size.hash_stable(hcx, hasher);
-                align.hash_stable(hcx, hasher);
-                primitive_align.hash_stable(hcx, hasher);
             }
         }
     }
@@ -2453,7 +2387,8 @@
                 element.hash_stable(hcx, hasher);
                 count.hash_stable(hcx, hasher);
             }
-            Aggregate { sized, size, align, primitive_align } => {
+            Aggregate { packed, sized, size, align, primitive_align } => {
+                packed.hash_stable(hcx, hasher);
                 sized.hash_stable(hcx, hasher);
                 size.hash_stable(hcx, hasher);
                 align.hash_stable(hcx, hasher);
@@ -2518,10 +2453,3 @@
     memory_index,
     min_size
 });
-
-impl_stable_hash_for!(struct ::ty::layout::Union {
-    align,
-    primitive_align,
-    min_size,
-    packed
-});
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index f59b372..dd5e975 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -753,11 +753,11 @@
                     bug!("failed to get layout for `{}`: {}", t, e)
                 });
 
-                if let Layout::General { ref variants, size, discr, .. } = *layout.layout {
+                if let Layout::General { ref variants, discr, .. } = *layout.layout {
                     let discr_size = discr.size(cx.tcx).bytes();
 
                     debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
-                      t, size.bytes(), layout);
+                      t, layout.size(cx.tcx).bytes(), layout);
 
                     let (largest, slargest, largest_index) = enum_definition.variants
                         .iter()
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 712108b..b727629 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -307,8 +307,8 @@
             }
 
             layout::Abi::Aggregate { .. } => {
-                if let Layout::Array { count, .. } = *self.layout {
-                    if count > 0 {
+                if let Layout::Array { .. } = *self.layout {
+                    if self.fields.count() > 0 {
                         return self.field(ccx, 0).homogeneous_aggregate(ccx);
                     }
                 }
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index ff66090..cd68d04 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -42,7 +42,7 @@
 //!   taken to it, implementing them for Rust seems difficult.
 
 use rustc::ty::{self, Ty};
-use rustc::ty::layout::{self, Align, HasDataLayout, LayoutOf, Size, FullLayout};
+use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Size, FullLayout};
 
 use context::CrateContext;
 use type_::Type;
@@ -72,11 +72,7 @@
         return;
     }
     match *l.layout {
-        layout::NullablePointer { .. } |
-        layout::General { .. } |
-        layout::UntaggedUnion { .. } => { }
-
-        layout::Univariant(ref variant) => {
+        layout::Univariant(_) => {
             let is_enum = if let ty::TyAdt(def, _) = t.sty {
                 def.is_enum()
             } else {
@@ -87,9 +83,11 @@
             } else {
                 l
             };
-            llty.set_struct_body(&struct_llfields(cx, variant_layout), variant.packed)
-        },
-        _ => bug!("This function cannot handle {} with layout {:#?}", t, l)
+            llty.set_struct_body(&struct_llfields(cx, variant_layout),
+                                 variant_layout.is_packed())
+        }
+
+        _ => {}
     }
 }
 
@@ -102,63 +100,44 @@
         return cx.llvm_type_of(value.to_ty(cx.tcx()));
     }
     match *l.layout {
-        layout::Univariant(ref variant) => {
+        layout::Univariant(_) => {
             match name {
                 None => {
-                    Type::struct_(cx, &struct_llfields(cx, l), variant.packed)
+                    Type::struct_(cx, &struct_llfields(cx, l), l.is_packed())
                 }
                 Some(name) => {
                     Type::named_struct(cx, name)
                 }
             }
         }
-        layout::UntaggedUnion(ref un) => {
-            // Use alignment-sized ints to fill all the union storage.
-            let fill = union_fill(cx, un.stride(), un.align);
+        _ => {
+            let align = l.align(cx);
+            let abi_align = align.abi();
+            let elem_ty = if let Some(ity) = layout::Integer::for_abi_align(cx, align) {
+                Type::from_integer(cx, ity)
+            } else {
+                let vec_align = cx.data_layout().vector_align(Size::from_bytes(abi_align));
+                assert_eq!(vec_align.abi(), abi_align);
+                Type::vector(&Type::i32(cx), abi_align / 4)
+            };
+
+            let size = l.size(cx).bytes();
+            assert_eq!(size % abi_align, 0);
+            let fill = Type::array(&elem_ty, size / abi_align);
             match name {
                 None => {
-                    Type::struct_(cx, &[fill], un.packed)
+                    Type::struct_(cx, &[fill], l.is_packed())
                 }
                 Some(name) => {
                     let mut llty = Type::named_struct(cx, name);
-                    llty.set_struct_body(&[fill], un.packed);
+                    llty.set_struct_body(&[fill], l.is_packed());
                     llty
                 }
             }
         }
-        layout::NullablePointer { size, align, .. } |
-        layout::General { size, align, .. } => {
-            let fill = union_fill(cx, size, align);
-            match name {
-                None => {
-                    Type::struct_(cx, &[fill], false)
-                }
-                Some(name) => {
-                    let mut llty = Type::named_struct(cx, name);
-                    llty.set_struct_body(&[fill], false);
-                    llty
-                }
-            }
-        }
-        _ => bug!("Unsupported type {} represented as {:#?}", t, l)
     }
 }
 
-fn union_fill(cx: &CrateContext, size: Size, align: Align) -> Type {
-    let abi_align = align.abi();
-    let elem_ty = if let Some(ity) = layout::Integer::for_abi_align(cx, align) {
-        Type::from_integer(cx, ity)
-    } else {
-        let vec_align = cx.data_layout().vector_align(Size::from_bytes(abi_align));
-        assert_eq!(vec_align.abi(), abi_align);
-        Type::vector(&Type::i32(cx), abi_align / 4)
-    };
-
-    let size = size.bytes();
-    assert_eq!(size % abi_align, 0);
-    Type::array(&elem_ty, size / abi_align)
-}
-
 /// Double an index and add 1 to account for padding.
 pub fn memory_index_to_gep(index: u64) -> u64 {
     1 + index * 2
@@ -166,17 +145,20 @@
 
 pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                  layout: FullLayout<'tcx>) -> Vec<Type> {
-    let variant = match *layout.layout {
-        layout::Univariant(ref variant) => variant,
-        _ => bug!("unexpected {:#?}", layout)
-    };
+    debug!("struct_llfields: {:#?}", layout);
+    let align = layout.align(cx);
+    let size = layout.size(cx);
     let field_count = layout.fields.count();
-    debug!("struct_llfields: variant: {:?}", variant);
+
     let mut offset = Size::from_bytes(0);
     let mut result: Vec<Type> = Vec::with_capacity(1 + field_count * 2);
-    for i in variant.field_index_by_increasing_offset() {
+    let field_index_by_increasing_offset = match *layout.layout {
+        layout::Univariant(ref variant) => variant.field_index_by_increasing_offset(),
+        _ => bug!("unexpected {:#?}", layout)
+    };
+    for i in field_index_by_increasing_offset {
         let field = layout.field(cx, i);
-        let target_offset = variant.offsets[i as usize];
+        let target_offset = layout.fields.offset(i as usize);
         debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?}",
             i, field, offset, target_offset);
         assert!(target_offset >= offset);
@@ -187,30 +169,30 @@
         let llty = cx.llvm_type_of(field.ty);
         result.push(llty);
 
-        if variant.packed {
+        if layout.is_packed() {
             assert_eq!(padding.bytes(), 0);
         } else {
             let field_align = field.align(cx);
-            assert!(field_align.abi() <= variant.align.abi(),
+            assert!(field_align.abi() <= align.abi(),
                     "non-packed type has field with larger align ({}): {:#?}",
-                    field_align.abi(), variant);
+                    field_align.abi(), layout);
         }
 
         offset = target_offset + field.size(cx);
     }
-    if variant.sized && field_count > 0 {
-        if offset > variant.stride() {
-            bug!("variant: {:?} stride: {:?} offset: {:?}",
-                variant, variant.stride(), offset);
+    if !layout.is_unsized() && field_count > 0 {
+        if offset > size {
+            bug!("layout: {:#?} stride: {:?} offset: {:?}",
+                 layout, size, offset);
         }
-        let padding = variant.stride() - offset;
-        debug!("struct_llfields: pad_bytes: {:?} offset: {:?} min_size: {:?} stride: {:?}",
-            padding, offset, variant.min_size, variant.stride());
+        let padding = size - offset;
+        debug!("struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}",
+               padding, offset, size);
         result.push(Type::array(&Type::i8(cx), padding.bytes()));
         assert!(result.len() == 1 + field_count * 2);
     } else {
-        debug!("struct_llfields: offset: {:?} min_size: {:?} stride: {:?}",
-               offset, variant.min_size, variant.stride());
+        debug!("struct_llfields: offset: {:?} stride: {:?}",
+               offset, size);
     }
 
     result
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index bc6ddef..82a4095 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -65,9 +65,9 @@
     let layout = ccx.layout_of(ty);
     match *layout.layout {
         Layout::FatPointer { .. } => true,
-        Layout::Univariant(ref variant) => {
+        Layout::Univariant(_) => {
             // There must be only 2 fields.
-            if variant.offsets.len() != 2 {
+            if layout.fields.count() != 2 {
                 return false;
             }
 
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 89f1bb6..b9ff461 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -939,20 +939,6 @@
     fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
                                       -> Vec<MemberDescription> {
         let layout = cx.layout_of(self.ty);
-
-        let tmp;
-        let offsets = match *layout.layout {
-            layout::Univariant(ref variant) => &variant.offsets,
-            layout::Vector { element, count } => {
-                let element_size = element.size(cx).bytes();
-                tmp = (0..count).
-                  map(|i| layout::Size::from_bytes(i*element_size))
-                  .collect::<Vec<layout::Size>>();
-                &tmp
-            }
-            _ => bug!("{} is not a struct", self.ty)
-        };
-
         self.variant.fields.iter().enumerate().map(|(i, f)| {
             let name = if self.variant.ctor_kind == CtorKind::Fn {
                 format!("__{}", i)
@@ -964,7 +950,7 @@
             MemberDescription {
                 name,
                 type_metadata: type_metadata(cx, field.ty, self.span),
-                offset: offsets[i],
+                offset: layout.fields.offset(i),
                 size,
                 align,
                 flags: DIFlags::FlagZero,
@@ -1022,18 +1008,12 @@
     fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
                                       -> Vec<MemberDescription> {
         let layout = cx.layout_of(self.ty);
-        let offsets = if let layout::Univariant(ref variant) = *layout.layout {
-            &variant.offsets
-        } else {
-            bug!("{} is not a tuple", self.ty);
-        };
-
         self.component_types.iter().enumerate().map(|(i, &component_type)| {
             let (size, align) = cx.size_and_align_of(component_type);
             MemberDescription {
                 name: format!("__{}", i),
                 type_metadata: type_metadata(cx, component_type, self.span),
-                offset: offsets[i],
+                offset: layout.fields.offset(i),
                 size,
                 align,
                 flags: DIFlags::FlagZero,
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 209083a..f374ed9 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -58,15 +58,9 @@
             let layout = ccx.layout_of(t);
             debug!("DST {} layout: {:?}", t, layout);
 
-            let (sized_size, sized_align) = match *layout.layout {
-                ty::layout::Layout::Univariant(ref variant) => {
-                    (variant.offsets.last().map_or(0, |o| o.bytes()), variant.align.abi())
-                }
-                _ => {
-                    bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}",
-                         t, layout);
-                }
-            };
+            let i = layout.fields.count() - 1;
+            let sized_size = layout.fields.offset(i).bytes();
+            let sized_align = layout.align(ccx).abi();
             debug!("DST {} statically sized prefix size: {} align: {}",
                    t, sized_size, sized_align);
             let sized_size = C_usize(ccx, sized_size);
@@ -74,7 +68,7 @@
 
             // Recurse to get the size of the dynamically sized field (must be
             // the last field).
-            let field_ty = layout.field(ccx, layout.fields.count() - 1).ty;
+            let field_ty = layout.field(ccx, i).ty;
             let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
 
             // FIXME (#26403, #27023): We should be adding padding
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 8924fc3..d6e2257 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -1108,14 +1108,14 @@
                 build_const_struct(ccx, l.for_variant(variant_index), vals, Some(discr))
             }
         }
-        layout::UntaggedUnion(ref un) => {
+        layout::UntaggedUnion => {
             assert_eq!(variant_index, 0);
             let contents = [
                 vals[0].llval,
-                padding(ccx, un.stride() - ccx.size_of(vals[0].ty))
+                padding(ccx, l.size(ccx) - ccx.size_of(vals[0].ty))
             ];
 
-            Const::new(C_struct(ccx, &contents, un.packed), t)
+            Const::new(C_struct(ccx, &contents, l.is_packed()), t)
         }
         layout::Univariant(_) => {
             assert_eq!(variant_index, 0);
@@ -1162,11 +1162,11 @@
         offset = ccx.size_of(discr.ty);
     }
 
-    let st = match *layout.layout {
-        layout::Univariant(ref variant) => variant,
+    let field_index_by_increasing_offset = match *layout.layout {
+        layout::Univariant(ref variant) => variant.field_index_by_increasing_offset(),
         _ => bug!("unexpected {:#?}", layout)
     };
-    let parts = st.field_index_by_increasing_offset().map(|i| {
+    let parts = field_index_by_increasing_offset.map(|i| {
         (vals[i], layout.fields.offset(i))
     });
     for (val, target_offset) in parts {
@@ -1178,7 +1178,7 @@
     // Pad to the size of the whole type, not e.g. the variant.
     cfields.push(padding(ccx, ccx.size_of(layout.ty) - offset));
 
-    Const::new(C_struct(ccx, &cfields, st.packed), layout.ty)
+    Const::new(C_struct(ccx, &cfields, layout.is_packed()), layout.ty)
 }
 
 fn padding(ccx: &CrateContext, size: Size) -> ValueRef {
diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs
index ab31bcd..b21e4ff 100644
--- a/src/librustc_trans/mir/lvalue.rs
+++ b/src/librustc_trans/mir/lvalue.rs
@@ -10,7 +10,7 @@
 
 use llvm::{self, ValueRef};
 use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::ty::layout::{self, Align, Layout, LayoutOf};
+use rustc::ty::layout::{self, Align, FullLayout, Layout, LayoutOf};
 use rustc::mir;
 use rustc::mir::tcx::LvalueTy;
 use rustc_data_structures::indexed_vec::Idx;
@@ -55,14 +55,9 @@
     }
 }
 
-impl<'a> From<&'a Layout<'a>> for Alignment {
-    fn from(layout: &Layout) -> Self {
-        let (packed, align) = match *layout {
-            Layout::UntaggedUnion(ref un) => (un.packed, un.align),
-            Layout::Univariant(ref variant) => (variant.packed, variant.align),
-            _ => return Alignment::AbiAligned
-        };
-        if packed {
+impl<'a> From<FullLayout<'a>> for Alignment {
+    fn from(layout: FullLayout) -> Self {
+        if let layout::Abi::Aggregate { packed: true, align, .. } = layout.abi {
             Alignment::Packed(align)
         } else {
             Alignment::AbiAligned
@@ -208,7 +203,7 @@
         let field = l.field(ccx, ix);
         let offset = l.fields.offset(ix).bytes();
 
-        let alignment = self.alignment | Alignment::from(l.layout);
+        let alignment = self.alignment | Alignment::from(l);
 
         // Unions and newtypes only use an offset of 0.
         match *l.layout {
@@ -267,16 +262,10 @@
             }
         };
 
-        // Check whether the variant being used is packed, if applicable.
-        let is_packed = match *l.layout {
-            layout::Univariant(ref variant) => variant.packed,
-            _ => return simple()
-        };
-
         // Simple case - we can just GEP the field
         //   * Packed struct - There is no alignment padding
         //   * Field is sized - pointer is properly aligned already
-        if is_packed || !field.is_unsized() {
+        if l.is_packed() || !field.is_unsized() {
             return simple();
         }
 
@@ -466,12 +455,13 @@
 
             // If this is an enum, cast to the appropriate variant struct type.
             let layout = bcx.ccx.layout_of(ty);
-            let variant_layout = layout.for_variant(variant_index);
-            match (layout.layout, variant_layout.layout) {
-                (&layout::NullablePointer { .. }, &layout::Univariant(ref st)) |
-                (&layout::General { .. }, &layout::Univariant(ref st)) => {
+            match *layout.layout {
+                layout::NullablePointer { .. } |
+                layout::General { .. } => {
+                    let variant_layout = layout.for_variant(variant_index);
                     let variant_ty = Type::struct_(bcx.ccx,
-                        &adt::struct_llfields(bcx.ccx, variant_layout), st.packed);
+                        &adt::struct_llfields(bcx.ccx, variant_layout),
+                        variant_layout.is_packed());
                     downcast.llval = bcx.pointercast(downcast.llval, variant_ty.ptr_to());
                 }
                 _ => {}
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index a71bcf4..a1e8901 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -12,7 +12,7 @@
 use llvm::{self, ValueRef, BasicBlockRef};
 use llvm::debuginfo::DIScope;
 use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::ty::layout::{self, LayoutOf};
+use rustc::ty::layout::LayoutOf;
 use rustc::mir::{self, Mir};
 use rustc::ty::subst::Substs;
 use rustc::infer::TransNormalize;
@@ -576,13 +576,8 @@
             };
 
             let layout = bcx.ccx.layout_of(closure_ty);
-            let offsets = match *layout.layout {
-                layout::Univariant(ref variant) => &variant.offsets[..],
-                _ => bug!("Closures are only supposed to be Univariant")
-            };
-
             for (i, (decl, ty)) in mir.upvar_decls.iter().zip(upvar_tys).enumerate() {
-                let byte_offset_of_var_in_env = offsets[i].bytes();
+                let byte_offset_of_var_in_env = layout.fields.offset(i).bytes();
 
                 let ops = unsafe {
                     [llvm::LLVMRustDIBuilderCreateOpDeref(),