about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/session/code_stats.rs7
-rw-r--r--src/librustc/ty/layout.rs430
-rw-r--r--src/librustc_data_structures/flock.rs6
-rw-r--r--src/librustc_lint/types.rs3
-rw-r--r--src/librustc_trans/adt.rs53
-rw-r--r--src/librustc_trans/base.rs7
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs57
-rw-r--r--src/librustc_trans/mir/block.rs10
-rw-r--r--src/librustc_trans/mir/operand.rs2
-rw-r--r--src/librustc_trans/mir/rvalue.rs12
-rw-r--r--src/test/debuginfo/borrowed-enum.rs4
-rw-r--r--src/test/debuginfo/by-value-non-immediate-argument.rs2
-rw-r--r--src/test/debuginfo/generic-struct-style-enum.rs6
-rw-r--r--src/test/debuginfo/generic-tuple-style-enum.rs6
-rw-r--r--src/test/debuginfo/struct-in-enum.rs4
-rw-r--r--src/test/debuginfo/struct-style-enum.rs6
-rw-r--r--src/test/debuginfo/tuple-style-enum.rs6
-rw-r--r--src/test/debuginfo/unique-enum.rs4
-rw-r--r--src/test/run-pass/closure-immediate.rs22
-rw-r--r--src/test/run-pass/enum-size-variance.rs3
-rw-r--r--src/test/run-pass/extern-pass-empty.rs3
-rw-r--r--src/test/run-pass/multiple-reprs.rs43
-rw-r--r--src/test/run-pass/nonzero-enum.rs3
-rw-r--r--src/test/run-pass/struct-return.rs2
-rw-r--r--src/test/run-pass/type-sizes.rs8
-rw-r--r--src/test/ui/print_type_sizes/nullable.stdout35
-rw-r--r--src/test/ui/print_type_sizes/packed.stdout10
-rw-r--r--src/test/ui/print_type_sizes/padding.stdout16
28 files changed, 538 insertions, 232 deletions
diff --git a/src/librustc/session/code_stats.rs b/src/librustc/session/code_stats.rs
index 8308c54d70b..a042b2abf3a 100644
--- a/src/librustc/session/code_stats.rs
+++ b/src/librustc/session/code_stats.rs
@@ -142,7 +142,12 @@ impl CodeStats {
                 max_variant_size = cmp::max(max_variant_size, size);
 
                 let mut min_offset = discr_size;
-                for field in fields {
+
+                // We want to print fields by increasing offset.
+                let mut fields = fields.clone();
+                fields.sort_by_key(|f| f.offset);
+
+                for field in fields.iter() {
                     let FieldInfo { ref name, offset, size, align } = *field;
 
                     // Include field alignment in output only if it caused padding injection
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 8646bccf1e9..53ed103ad91 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -24,6 +24,7 @@ use syntax_pos::DUMMY_SP;
 use std::cmp;
 use std::fmt;
 use std::i64;
+use std::iter;
 
 /// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
 /// for a target, which contains everything needed to compute layouts.
@@ -415,7 +416,7 @@ impl Integer {
     /// signed discriminant range and #[repr] attribute.
     /// N.B.: u64 values above i64::MAX will be treated as signed, but
     /// that shouldn't affect anything, other than maybe debuginfo.
-    pub fn repr_discr(tcx: TyCtxt, ty: Ty, hint: attr::ReprAttr, min: i64, max: i64)
+    fn repr_discr(tcx: TyCtxt, ty: Ty, hints: &[attr::ReprAttr], min: i64, max: i64)
                       -> (Integer, bool) {
         // Theoretically, negative values could be larger in unsigned representation
         // than the unsigned representation of the signed minimum. However, if there
@@ -424,34 +425,41 @@ impl Integer {
         let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u64, max as u64));
         let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
 
-        let at_least = match hint {
-            attr::ReprInt(ity) => {
-                let discr = Integer::from_attr(&tcx.data_layout, ity);
-                let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
-                if discr < fit {
-                    bug!("Integer::repr_discr: `#[repr]` hint too small for \
-                          discriminant range of enum `{}", ty)
+        let mut min_from_extern = None;
+        let min_default = I8;
+
+        for &r in hints.iter() {
+            match r {
+                attr::ReprInt(ity) => {
+                    let discr = Integer::from_attr(&tcx.data_layout, ity);
+                    let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
+                    if discr < fit {
+                        bug!("Integer::repr_discr: `#[repr]` hint too small for \
+                              discriminant range of enum `{}", ty)
+                    }
+                    return (discr, ity.is_signed());
                 }
-                return (discr, ity.is_signed());
-            }
-            attr::ReprExtern => {
-                match &tcx.sess.target.target.arch[..] {
-                    // WARNING: the ARM EABI has two variants; the one corresponding
-                    // to `at_least == I32` appears to be used on Linux and NetBSD,
-                    // but some systems may use the variant corresponding to no
-                    // lower bound.  However, we don't run on those yet...?
-                    "arm" => I32,
-                    _ => I32,
+                attr::ReprExtern => {
+                    match &tcx.sess.target.target.arch[..] {
+                        // WARNING: the ARM EABI has two variants; the one corresponding
+                        // to `at_least == I32` appears to be used on Linux and NetBSD,
+                        // but some systems may use the variant corresponding to no
+                        // lower bound.  However, we don't run on those yet...?
+                        "arm" => min_from_extern = Some(I32),
+                        _ => min_from_extern = Some(I32),
+                    }
+                }
+                attr::ReprAny => {},
+                attr::ReprPacked => {
+                    bug!("Integer::repr_discr: found #[repr(packed)] on enum `{}", ty);
+                }
+                attr::ReprSimd => {
+                    bug!("Integer::repr_discr: found #[repr(simd)] on enum `{}", ty);
                 }
             }
-            attr::ReprAny => I8,
-            attr::ReprPacked => {
-                bug!("Integer::repr_discr: found #[repr(packed)] on enum `{}", ty);
-            }
-            attr::ReprSimd => {
-                bug!("Integer::repr_discr: found #[repr(simd)] on enum `{}", ty);
-            }
-        };
+        }
+
+        let at_least = min_from_extern.unwrap_or(min_default);
 
         // If there are no negative values, we can use the unsigned fit.
         if min >= 0 {
@@ -511,70 +519,158 @@ pub struct Struct {
     /// If true, the size is exact, otherwise it's only a lower bound.
     pub sized: bool,
 
-    /// Offsets for the first byte of each field.
+    /// 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>,
 
+    /// 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,
 }
 
+// Info required to optimize struct layout.
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
+enum StructKind {
+    // A tuple, closure, or univariant which cannot be coerced to unsized.
+    AlwaysSizedUnivariant,
+    // A univariant, the last field of which may be coerced to unsized.
+    MaybeUnsizedUnivariant,
+    // A univariant, but part of an enum.
+    EnumVariant,
+}
+
 impl<'a, 'gcx, 'tcx> Struct {
-    pub fn new(dl: &TargetDataLayout, packed: bool) -> Struct {
-        Struct {
+    // FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type.
+    fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
+                  reprs: &[attr::ReprAttr], kind: StructKind,
+                  scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
+        let packed = reprs.contains(&attr::ReprPacked);
+        let mut ret = Struct {
             align: if packed { dl.i8_align } else { dl.aggregate_align },
             packed: packed,
             sized: true,
             offsets: vec![],
+            memory_index: vec![],
             min_size: Size::from_bytes(0),
+        };
+
+        // Anything with ReprExtern or ReprPacked doesn't optimize.
+        // Neither do  1-member and 2-member structs.
+        // In addition, code in trans assume that 2-element structs can become pairs.
+        // It's easier to just short-circuit here.
+        let mut can_optimize = fields.len() > 2 || StructKind::EnumVariant == kind;
+        if can_optimize {
+            // This exhaustive match makes new reprs force the adder to modify this function.
+            // Otherwise, things can silently break.
+            // Note the inversion, return true to stop optimizing.
+            can_optimize = !reprs.iter().any(|r| {
+                match *r {
+                    attr::ReprAny | attr::ReprInt(_) => false,
+                    attr::ReprExtern | attr::ReprPacked => true,
+                    attr::ReprSimd => bug!("Simd  vectors should be represented as layout::Vector")
+                }
+            });
         }
-    }
 
-    /// Extend the Struct with more fields.
-    pub fn extend<I>(&mut self, dl: &TargetDataLayout,
-                     fields: I,
-                     scapegoat: Ty<'gcx>)
-                     -> Result<(), LayoutError<'gcx>>
-    where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
-        self.offsets.reserve(fields.size_hint().0);
+        let (optimize, sort_ascending) = match kind {
+            StructKind::AlwaysSizedUnivariant => (can_optimize, false),
+            StructKind::MaybeUnsizedUnivariant => (can_optimize, false),
+            StructKind::EnumVariant => {
+                assert!(fields.len() >= 1, "Enum variants must have discriminants.");
+                (can_optimize && fields[0].size(dl).bytes() == 1, true)
+            }
+        };
 
-        let mut offset = self.min_size;
+        ret.offsets = vec![Size::from_bytes(0); fields.len()];
+        let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
 
-        for field in fields {
-            if !self.sized {
-                bug!("Struct::extend: field #{} of `{}` comes after unsized field",
-                     self.offsets.len(), scapegoat);
+        if optimize {
+            let start = if let StructKind::EnumVariant = kind { 1 } else { 0 };
+            let end = if let StructKind::MaybeUnsizedUnivariant = kind {
+                fields.len() - 1
+            } else {
+                fields.len()
+            };
+            if end > start {
+                let optimizing  = &mut inverse_memory_index[start..end];
+                if sort_ascending {
+                    optimizing.sort_by_key(|&x| fields[x as usize].align(dl).abi());
+                } else {
+                    optimizing.sort_by(| &a, &b | {
+                        let a = fields[a as usize].align(dl).abi();
+                        let b = fields[b as usize].align(dl).abi();
+                        b.cmp(&a)
+                    });
+                }
+            }
+        }
+
+        // inverse_memory_index holds field indices by increasing memory offset.
+        // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5.
+        // We now write field offsets to the corresponding offset slot;
+        // field 5 with offset 0 puts 0 in offsets[5].
+        // At the bottom of this function, we use inverse_memory_index to produce memory_index.
+
+        if let StructKind::EnumVariant = kind {
+            assert_eq!(inverse_memory_index[0], 0,
+              "Enum variant discriminants must have the lowest offset.");
+        }
+
+        let mut offset = Size::from_bytes(0);
+
+        for i in inverse_memory_index.iter() {
+            let field = fields[*i as usize];
+            if !ret.sized {
+                bug!("Struct::new: field #{} of `{}` comes after unsized field",
+                     ret.offsets.len(), scapegoat);
             }
 
-            let field = field?;
             if field.is_unsized() {
-                self.sized = false;
+                ret.sized = false;
             }
 
             // Invariant: offset < dl.obj_size_bound() <= 1<<61
-            if !self.packed {
+            if !ret.packed {
                 let align = field.align(dl);
-                self.align = self.align.max(align);
+                ret.align = ret.align.max(align);
                 offset = offset.abi_align(align);
             }
 
-            self.offsets.push(offset);
-
-            debug!("Struct::extend offset: {:?} field: {:?} {:?}", offset, field, field.size(dl));
+            debug!("Struct::new offset: {:?} field: {:?} {:?}", offset, field, field.size(dl));
+            ret.offsets[*i as usize] = offset;
 
             offset = offset.checked_add(field.size(dl), dl)
                            .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?;
         }
 
-        debug!("Struct::extend min_size: {:?}", offset);
 
-        self.min_size = offset;
+        debug!("Struct::new min_size: {:?}", offset);
+        ret.min_size = offset;
 
-        Ok(())
-    }
+        // As stated above, inverse_memory_index holds field indices by increasing offset.
+        // This makes it an already-sorted view of the offsets vec.
+        // To invert it, consider:
+        // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
+        // Field 5 would be the first element, so memory_index is i:
+        // Note: if we didn't optimize, it's already right.
 
-    /// Get the size without trailing alignment padding.
+        if optimize {
+            ret.memory_index = vec![0; inverse_memory_index.len()];
 
-    /// Get the size with trailing aligment padding.
+            for i in 0..inverse_memory_index.len() {
+                ret.memory_index[inverse_memory_index[i] as usize]  = i as u32;
+            }
+        } else {
+            ret.memory_index = inverse_memory_index;
+        }
+
+        Ok(ret)
+    }
+
+    /// Get the size with trailing alignment padding.
     pub fn stride(&self) -> Size {
         self.min_size.abi_align(self.align)
     }
@@ -592,18 +688,45 @@ impl<'a, 'gcx, 'tcx> Struct {
         Ok(true)
     }
 
+    /// Get indices of the tys that made this struct by increasing offset.
+    #[inline]
+    pub fn field_index_by_increasing_offset<'b>(&'b self) -> impl iter::Iterator<Item=usize>+'b {
+        let mut inverse_small = [0u8; 64];
+        let mut inverse_big = vec![];
+        let use_small = self.memory_index.len() <= inverse_small.len();
+
+        // We have to write this logic twice in order to keep the array small.
+        if use_small {
+            for i in 0..self.memory_index.len() {
+                inverse_small[self.memory_index[i] as usize] = i as u8;
+            }
+        } else {
+            inverse_big = vec![0; self.memory_index.len()];
+            for i in 0..self.memory_index.len() {
+                inverse_big[self.memory_index[i] as usize] = i as u32;
+            }
+        }
+
+        (0..self.memory_index.len()).map(move |i| {
+            if use_small { inverse_small[i] as usize }
+            else { inverse_big[i] as usize }
+        })
+    }
+
     /// Find the path leading to a non-zero leaf field, starting from
     /// the given type and recursing through aggregates.
+    /// The tuple is `(path, source_path)`,
+    /// where `path` is in memory order and `source_path` in source order.
     // FIXME(eddyb) track value ranges and traverse already optimized enums.
-    pub fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                  ty: Ty<'gcx>)
-                                  -> Result<Option<FieldPath>, LayoutError<'gcx>> {
+    fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                               ty: Ty<'gcx>)
+                               -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>> {
         let tcx = infcx.tcx.global_tcx();
         match (ty.layout(infcx)?, &ty.sty) {
             (&Scalar { non_zero: true, .. }, _) |
-            (&CEnum { non_zero: true, .. }, _) => Ok(Some(vec![])),
+            (&CEnum { non_zero: true, .. }, _) => Ok(Some((vec![], vec![]))),
             (&FatPointer { non_zero: true, .. }, _) => {
-                Ok(Some(vec![FAT_PTR_ADDR as u32]))
+                Ok(Some((vec![FAT_PTR_ADDR as u32], vec![FAT_PTR_ADDR as u32])))
             }
 
             // Is this the NonZero lang item wrapping a pointer or integer type?
@@ -614,10 +737,11 @@ impl<'a, 'gcx, 'tcx> Struct {
                     // FIXME(eddyb) also allow floating-point types here.
                     Scalar { value: Int(_), non_zero: false } |
                     Scalar { value: Pointer, non_zero: false } => {
-                        Ok(Some(vec![0]))
+                        Ok(Some((vec![0], vec![0])))
                     }
                     FatPointer { non_zero: false, .. } => {
-                        Ok(Some(vec![FAT_PTR_ADDR as u32, 0]))
+                        let tmp = vec![FAT_PTR_ADDR as u32, 0];
+                        Ok(Some((tmp.clone(), tmp)))
                     }
                     _ => Ok(None)
                 }
@@ -625,27 +749,30 @@ impl<'a, 'gcx, 'tcx> Struct {
 
             // Perhaps one of the fields of this struct is non-zero
             // let's recurse and find out
-            (_, &ty::TyAdt(def, substs)) if def.is_struct() => {
-                Struct::non_zero_field_path(infcx, def.struct_variant().fields
+            (&Univariant { ref variant, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => {
+                Struct::non_zero_field_paths(infcx, def.struct_variant().fields
                                                       .iter().map(|field| {
                     field.ty(tcx, substs)
-                }))
+                }),
+                Some(&variant.memory_index[..]))
             }
 
             // Perhaps one of the upvars of this closure is non-zero
-            // Let's recurse and find out!
-            (_, &ty::TyClosure(def_id, ref substs)) => {
-                Struct::non_zero_field_path(infcx, substs.upvar_tys(def_id, tcx))
+            (&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => {
+                let upvar_tys = substs.upvar_tys(def, tcx);
+                Struct::non_zero_field_paths(infcx, upvar_tys,
+                    Some(&variant.memory_index[..]))
             }
             // Can we use one of the fields in this tuple?
-            (_, &ty::TyTuple(tys)) => {
-                Struct::non_zero_field_path(infcx, tys.iter().cloned())
+            (&Univariant { ref variant, .. }, &ty::TyTuple(tys)) => {
+                Struct::non_zero_field_paths(infcx, tys.iter().cloned(),
+                    Some(&variant.memory_index[..]))
             }
 
             // Is this a fixed-size array of something non-zero
             // with at least one element?
             (_, &ty::TyArray(ety, d)) if d > 0 => {
-                Struct::non_zero_field_path(infcx, Some(ety).into_iter())
+                Struct::non_zero_field_paths(infcx, Some(ety).into_iter(), None)
             }
 
             (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
@@ -663,14 +790,23 @@ impl<'a, 'gcx, 'tcx> Struct {
 
     /// Find the path leading to a non-zero leaf field, starting from
     /// the given set of fields and recursing through aggregates.
-    pub fn non_zero_field_path<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                  fields: I)
-                                  -> Result<Option<FieldPath>, LayoutError<'gcx>>
+    /// Returns Some((path, source_path)) on success.
+    /// `path` is translated to memory order. `source_path` is not.
+    fn non_zero_field_paths<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                  fields: I,
+                                  permutation: Option<&[u32]>)
+                                  -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>>
     where I: Iterator<Item=Ty<'gcx>> {
         for (i, ty) in fields.enumerate() {
-            if let Some(mut path) = Struct::non_zero_field_in_type(infcx, ty)? {
-                path.push(i as u32);
-                return Ok(Some(path));
+            if let Some((mut path, mut source_path)) = Struct::non_zero_field_in_type(infcx, ty)? {
+                source_path.push(i as u32);
+                let index = if let Some(p) = permutation {
+                    p[i] as usize
+                } else {
+                    i
+                };
+                path.push(index as u32);
+                return Ok(Some((path, source_path)));
             }
         }
         Ok(None)
@@ -723,7 +859,7 @@ impl<'a, 'gcx, 'tcx> Union {
         Ok(())
     }
 
-    /// Get the size with trailing aligment padding.
+    /// Get the size with trailing alignment padding.
     pub fn stride(&self) -> Size {
         self.min_size.abi_align(self.align)
     }
@@ -833,7 +969,9 @@ pub enum Layout {
         nndiscr: u64,
         nonnull: Struct,
         // N.B. There is a 0 at the start, for LLVM GEP through a pointer.
-        discrfield: FieldPath
+        discrfield: FieldPath,
+        // Like discrfield, but in source order. For debuginfo.
+        discrfield_source: FieldPath
     }
 }
 
@@ -887,6 +1025,7 @@ impl<'a, 'gcx, 'tcx> Layout {
         let dl = &tcx.data_layout;
         assert!(!ty.has_infer_types());
 
+
         let layout = match ty.sty {
             // Basic scalars.
             ty::TyBool => Scalar { value: Int(I1), non_zero: false },
@@ -908,7 +1047,11 @@ impl<'a, 'gcx, 'tcx> Layout {
             ty::TyFnPtr(_) => Scalar { value: Pointer, non_zero: true },
 
             // The never type.
-            ty::TyNever => Univariant { variant: Struct::new(dl, false), non_zero: false },
+            ty::TyNever => Univariant {
+                variant: Struct::new(dl, &vec![], &[],
+                  StructKind::AlwaysSizedUnivariant, ty)?,
+                non_zero: false
+            },
 
             // Potentially-fat pointers.
             ty::TyBox(pointee) |
@@ -959,27 +1102,36 @@ impl<'a, 'gcx, 'tcx> Layout {
             // Odd unit types.
             ty::TyFnDef(..) => {
                 Univariant {
-                    variant: Struct::new(dl, false),
+                    variant: Struct::new(dl, &vec![],
+                      &[], StructKind::AlwaysSizedUnivariant, ty)?,
                     non_zero: false
                 }
             }
             ty::TyDynamic(..) => {
-                let mut unit = Struct::new(dl, false);
+                let mut unit = Struct::new(dl, &vec![], &[],
+                  StructKind::AlwaysSizedUnivariant, ty)?;
                 unit.sized = false;
                 Univariant { variant: unit, non_zero: false }
             }
 
             // Tuples and closures.
             ty::TyClosure(def_id, ref substs) => {
-                let mut st = Struct::new(dl, false);
                 let tys = substs.upvar_tys(def_id, tcx);
-                st.extend(dl, tys.map(|ty| ty.layout(infcx)), ty)?;
+                let st = Struct::new(dl,
+                    &tys.map(|ty| ty.layout(infcx))
+                      .collect::<Result<Vec<_>, _>>()?,
+                    &[],
+                    StructKind::AlwaysSizedUnivariant, ty)?;
                 Univariant { variant: st, non_zero: false }
             }
 
             ty::TyTuple(tys) => {
-                let mut st = Struct::new(dl, false);
-                st.extend(dl, tys.iter().map(|ty| ty.layout(infcx)), ty)?;
+                // FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked.
+                // See the univariant case below to learn how.
+                let st = Struct::new(dl,
+                    &tys.iter().map(|ty| ty.layout(infcx))
+                      .collect::<Result<Vec<_>, _>>()?,
+                    &[], StructKind::AlwaysSizedUnivariant, ty)?;
                 Univariant { variant: st, non_zero: false }
             }
 
@@ -1003,16 +1155,16 @@ impl<'a, 'gcx, 'tcx> Layout {
 
             // ADTs.
             ty::TyAdt(def, substs) => {
-                let hint = *tcx.lookup_repr_hints(def.did).get(0)
-                    .unwrap_or(&attr::ReprAny);
+                let hints = &tcx.lookup_repr_hints(def.did)[..];
 
                 if def.variants.is_empty() {
                     // Uninhabitable; represent as unit
                     // (Typechecking will reject discriminant-sizing attrs.)
-                    assert_eq!(hint, attr::ReprAny);
+                    assert_eq!(hints.len(), 0);
 
                     return success(Univariant {
-                        variant: Struct::new(dl, false),
+                        variant: Struct::new(dl, &vec![],
+                          &hints[..], StructKind::AlwaysSizedUnivariant, ty)?,
                         non_zero: false
                     });
                 }
@@ -1027,7 +1179,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                         if x > max { max = x; }
                     }
 
-                    let (discr, signed) = Integer::repr_discr(tcx, ty, hint, min, max);
+                    let (discr, signed) = Integer::repr_discr(tcx, ty, &hints[..], min, max);
                     return success(CEnum {
                         discr: discr,
                         signed: signed,
@@ -1037,21 +1189,35 @@ impl<'a, 'gcx, 'tcx> Layout {
                     });
                 }
 
-                if !def.is_enum() || def.variants.len() == 1 && hint == attr::ReprAny {
+                if !def.is_enum() || def.variants.len() == 1 && hints.is_empty() {
                     // Struct, or union, or univariant enum equivalent to a struct.
                     // (Typechecking will reject discriminant-sizing attrs.)
 
+                    let kind = if def.is_enum() || def.variants[0].fields.len() == 0{
+                        StructKind::AlwaysSizedUnivariant
+                    } else {
+                        use middle::region::ROOT_CODE_EXTENT;
+                        let param_env = tcx.construct_parameter_environment(DUMMY_SP,
+                          def.did, ROOT_CODE_EXTENT);
+                        let fields = &def.variants[0].fields;
+                        let last_field = &fields[fields.len()-1];
+                        let always_sized = last_field.ty(tcx, param_env.free_substs)
+                          .is_sized(tcx, &param_env, DUMMY_SP);
+                        if !always_sized { StructKind::MaybeUnsizedUnivariant }
+                        else { StructKind::AlwaysSizedUnivariant }
+                    };
+
                     let fields = def.variants[0].fields.iter().map(|field| {
                         field.ty(tcx, substs).layout(infcx)
-                    });
+                    }).collect::<Result<Vec<_>, _>>()?;
                     let packed = tcx.lookup_packed(def.did);
                     let layout = if def.is_union() {
                         let mut un = Union::new(dl, packed);
-                        un.extend(dl, fields, ty)?;
+                        un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?;
                         UntaggedUnion { variants: un }
                     } else {
-                        let mut st = Struct::new(dl, packed);
-                        st.extend(dl, fields, ty)?;
+                        let st = Struct::new(dl, &fields, &hints[..],
+                          kind, ty)?;
                         let non_zero = Some(def.did) == tcx.lang_items.non_zero();
                         Univariant { variant: st, non_zero: non_zero }
                     };
@@ -1073,7 +1239,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                     v.fields.iter().map(|field| field.ty(tcx, substs)).collect::<Vec<_>>()
                 }).collect::<Vec<_>>();
 
-                if variants.len() == 2 && hint == attr::ReprAny {
+                if variants.len() == 2 && hints.is_empty() {
                     // Nullable pointer optimization
                     for discr in 0..2 {
                         let other_fields = variants[1 - discr].iter().map(|ty| {
@@ -1082,9 +1248,11 @@ impl<'a, 'gcx, 'tcx> Layout {
                         if !Struct::would_be_zero_sized(dl, other_fields)? {
                             continue;
                         }
-                        let path = Struct::non_zero_field_path(infcx,
-                            variants[discr].iter().cloned())?;
-                        let mut path = if let Some(p) = path { p } else { continue };
+                        let paths = Struct::non_zero_field_paths(infcx,
+                            variants[discr].iter().cloned(),
+                            None)?;
+                        let (mut path, mut path_source) = if let Some(p) = paths { p }
+                          else { continue };
 
                         // FIXME(eddyb) should take advantage of a newtype.
                         if path == &[0] && variants[discr].len() == 1 {
@@ -1101,14 +1269,25 @@ impl<'a, 'gcx, 'tcx> Layout {
                             });
                         }
 
+                        let st = Struct::new(dl,
+                            &variants[discr].iter().map(|ty| ty.layout(infcx))
+                              .collect::<Result<Vec<_>, _>>()?,
+                            &hints[..], StructKind::AlwaysSizedUnivariant, ty)?;
+
+                        // We have to fix the last element of path here.
+                        let mut i = *path.last().unwrap();
+                        i = st.memory_index[i as usize];
+                        *path.last_mut().unwrap() = i;
                         path.push(0); // For GEP through a pointer.
                         path.reverse();
-                        let mut st = Struct::new(dl, false);
-                        st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?;
+                        path_source.push(0);
+                        path_source.reverse();
+
                         return success(StructWrappedNullablePointer {
                             nndiscr: discr as u64,
                             nonnull: st,
-                            discrfield: path
+                            discrfield: path,
+                            discrfield_source: path_source
                         });
                     }
                 }
@@ -1116,7 +1295,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                 // The general case.
                 let discr_max = (variants.len() - 1) as i64;
                 assert!(discr_max >= 0);
-                let (min_ity, _) = Integer::repr_discr(tcx, ty, hint, 0, discr_max);
+                let (min_ity, _) = Integer::repr_discr(tcx, ty, &hints[..], 0, discr_max);
 
                 let mut align = dl.aggregate_align;
                 let mut size = Size::from_bytes(0);
@@ -1126,24 +1305,26 @@ impl<'a, 'gcx, 'tcx> Layout {
 
                 // Create the set of structs that represent each variant
                 // Use the minimum integer type we figured out above
-                let discr = Some(Scalar { value: Int(min_ity), non_zero: false });
+                let discr = Scalar { value: Int(min_ity), non_zero: false };
                 let mut variants = variants.into_iter().map(|fields| {
-                    let mut found_start = false;
-                    let fields = fields.into_iter().map(|field| {
-                        let field = field.layout(infcx)?;
-                        if !found_start {
-                            // Find the first field we can't move later
-                            // to make room for a larger discriminant.
-                            let field_align = field.align(dl);
-                            if field.size(dl).bytes() != 0 || field_align.abi() != 1 {
-                                start_align = start_align.min(field_align);
-                                found_start = true;
-                            }
+                    let mut fields = fields.into_iter().map(|field| {
+                        field.layout(infcx)
+                    }).collect::<Result<Vec<_>, _>>()?;
+                    fields.insert(0, &discr);
+                    let st = Struct::new(dl,
+                        &fields,
+                        &hints[..], StructKind::EnumVariant, ty)?;
+                    // Find the first field we can't move later
+                    // to make room for a larger discriminant.
+                    // It is important to skip the first field.
+                    for i in st.field_index_by_increasing_offset().skip(1) {
+                        let field = fields[i];
+                        let field_align = field.align(dl);
+                        if field.size(dl).bytes() != 0 || field_align.abi() != 1 {
+                            start_align = start_align.min(field_align);
+                            break;
                         }
-                        Ok(field)
-                    });
-                    let mut st = Struct::new(dl, false);
-                    st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?;
+                    }
                     size = cmp::max(size, st.min_size);
                     align = align.max(st.align);
                     Ok(st)
@@ -1177,11 +1358,12 @@ impl<'a, 'gcx, 'tcx> Layout {
                     let old_ity_size = Int(min_ity).size(dl);
                     let new_ity_size = Int(ity).size(dl);
                     for variant in &mut variants {
-                        for offset in &mut variant.offsets[1..] {
-                            if *offset > old_ity_size {
-                                break;
+                        for i in variant.offsets.iter_mut() {
+                            // The first field is the discrimminant, at offset 0.
+                            // These aren't in order, and we need to skip it.
+                            if *i <= old_ity_size && *i > Size::from_bytes(0) {
+                                *i = new_ity_size;
                             }
-                            *offset = new_ity_size;
                         }
                         // We might be making the struct larger.
                         if variant.min_size <= old_ity_size {
diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs
index 510c9ceef09..33d71ba8626 100644
--- a/src/librustc_data_structures/flock.rs
+++ b/src/librustc_data_structures/flock.rs
@@ -31,6 +31,7 @@ mod imp {
     mod os {
         use libc;
 
+        #[repr(C)]
         pub struct flock {
             pub l_type: libc::c_short,
             pub l_whence: libc::c_short,
@@ -53,6 +54,7 @@ mod imp {
     mod os {
         use libc;
 
+        #[repr(C)]
         pub struct flock {
             pub l_start: libc::off_t,
             pub l_len: libc::off_t,
@@ -76,6 +78,7 @@ mod imp {
     mod os {
         use libc;
 
+        #[repr(C)]
         pub struct flock {
             pub l_start: libc::off_t,
             pub l_len: libc::off_t,
@@ -98,6 +101,7 @@ mod imp {
     mod os {
         use libc;
 
+        #[repr(C)]
         pub struct flock {
             pub l_type: libc::c_short,
             pub l_whence: libc::c_short,
@@ -119,6 +123,7 @@ mod imp {
     mod os {
         use libc;
 
+        #[repr(C)]
         pub struct flock {
             pub l_start: libc::off_t,
             pub l_len: libc::off_t,
@@ -141,6 +146,7 @@ mod imp {
     mod os {
         use libc;
 
+        #[repr(C)]
         pub struct flock {
             pub l_type: libc::c_short,
             pub l_whence: libc::c_short,
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 5e9fdbfa073..751c9c3440f 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -750,7 +750,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
                 if let Layout::General { ref variants, ref size, discr, .. } = *layout {
                     let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes();
 
-                    debug!("enum `{}` is {} bytes large", t, size.bytes());
+                    debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
+                      t, size.bytes(), layout);
 
                     let (largest, slargest, largest_index) = enum_definition.variants
                         .iter()
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 8ee362bae35..9c82e250773 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -151,14 +151,14 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         | layout::UntaggedUnion { .. } | layout::RawNullablePointer { .. } => { }
         layout::Univariant { ..}
         | layout::StructWrappedNullablePointer { .. } => {
-            let (nonnull_variant, packed) = match *l {
-                layout::Univariant { ref variant, .. } => (0, variant.packed),
+            let (nonnull_variant_index, nonnull_variant, packed) = match *l {
+                layout::Univariant { ref variant, .. } => (0, variant, variant.packed),
                 layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } =>
-                    (nndiscr, nonnull.packed),
+                    (nndiscr, nonnull, nonnull.packed),
                 _ => unreachable!()
             };
-            let fields = compute_fields(cx, t, nonnull_variant as usize, true);
-            llty.set_struct_body(&struct_llfields(cx, &fields, false, false),
+            let fields = compute_fields(cx, t, nonnull_variant_index as usize, true);
+            llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant, false, false),
                                  packed)
         },
         _ => bug!("This function cannot handle {} with layout {:#?}", t, l)
@@ -188,7 +188,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let fields = compute_fields(cx, t, nndiscr as usize, false);
             match name {
                 None => {
-                    Type::struct_(cx, &struct_llfields(cx, &fields, sizing, dst),
+                    Type::struct_(cx, &struct_llfields(cx, &fields, nonnull, sizing, dst),
                                   nonnull.packed)
                 }
                 Some(name) => {
@@ -203,7 +203,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let fields = compute_fields(cx, t, 0, true);
             match name {
                 None => {
-                    let fields = struct_llfields(cx, &fields, sizing, dst);
+                    let fields = struct_llfields(cx, &fields, &variant, sizing, dst);
                     Type::struct_(cx, &fields, variant.packed)
                 }
                 Some(name) => {
@@ -291,12 +291,14 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type {
 
 
 fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec<Ty<'tcx>>,
+                             variant: &layout::Struct,
                              sizing: bool, dst: bool) -> Vec<Type> {
+    let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]);
     if sizing {
-        fields.iter().filter(|&ty| !dst || type_is_sized(cx.tcx(), *ty))
-            .map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
+        fields.filter(|ty| !dst || type_is_sized(cx.tcx(), *ty))
+            .map(|ty| type_of::sizing_type_of(cx, ty)).collect()
     } else {
-        fields.iter().map(|&ty| type_of::in_memory_type_of(cx, ty)).collect()
+        fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect()
     }
 }
 
@@ -564,16 +566,16 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
 fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
                                 st: &layout::Struct, fields: &Vec<Ty<'tcx>>, val: MaybeSizedValue,
                                 ix: usize, needs_cast: bool) -> ValueRef {
-    let ccx = bcx.ccx();
     let fty = fields[ix];
+    let ccx = bcx.ccx();
     let ll_fty = type_of::in_memory_type_of(bcx.ccx(), fty);
     if bcx.is_unreachable() {
         return C_undef(ll_fty.ptr_to());
     }
 
     let ptr_val = if needs_cast {
-        let fields = fields.iter().map(|&ty| {
-            type_of::in_memory_type_of(ccx, ty)
+        let fields = st.field_index_by_increasing_offset().map(|i| {
+            type_of::in_memory_type_of(ccx, fields[i])
         }).collect::<Vec<_>>();
         let real_ty = Type::struct_(ccx, &fields[..], st.packed);
         bcx.pointercast(val.value, real_ty.ptr_to())
@@ -585,15 +587,15 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
     //   * First field - Always aligned properly
     //   * Packed struct - There is no alignment padding
     //   * Field is sized - pointer is properly aligned already
-    if ix == 0 || st.packed || type_is_sized(bcx.tcx(), fty) {
-        return bcx.struct_gep(ptr_val, ix);
+    if st.offsets[ix] == layout::Size::from_bytes(0) || st.packed || type_is_sized(bcx.tcx(), fty) {
+        return bcx.struct_gep(ptr_val, st.memory_index[ix] as usize);
     }
 
     // If the type of the last field is [T] or str, then we don't need to do
     // any adjusments
     match fty.sty {
         ty::TySlice(..) | ty::TyStr => {
-            return bcx.struct_gep(ptr_val, ix);
+            return bcx.struct_gep(ptr_val, st.memory_index[ix] as usize);
         }
         _ => ()
     }
@@ -755,8 +757,12 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // offset of current value
     let mut offset = 0;
     let mut cfields = Vec::new();
-    let offsets = st.offsets.iter().map(|i| i.bytes());
-    for (&val, target_offset) in vals.iter().zip(offsets) {
+    cfields.reserve(st.offsets.len()*2);
+
+    let parts = st.field_index_by_increasing_offset().map(|i| {
+        (&vals[i], st.offsets[i].bytes())
+    });
+    for (&val, target_offset) in parts {
         if offset < target_offset {
             cfields.push(padding(ccx, target_offset - offset));
             offset = target_offset;
@@ -807,14 +813,11 @@ pub fn const_get_field<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
     let l = ccx.layout_of(t);
     match *l {
         layout::CEnum { .. } => bug!("element access in C-like enum const"),
-        layout::Univariant { .. } | layout::Vector { .. } => const_struct_field(val, ix),
+        layout::Univariant { ref variant, .. } => {
+            const_struct_field(val, variant.memory_index[ix] as usize)
+        }
+        layout::Vector { .. } => const_struct_field(val, ix),
         layout::UntaggedUnion { .. } => const_struct_field(val, 0),
-        layout::General { .. } => const_struct_field(val, ix + 1),
-        layout::RawNullablePointer { .. } => {
-            assert_eq!(ix, 0);
-            val
-        },
-        layout::StructWrappedNullablePointer{ .. } => const_struct_field(val, ix),
         _ => bug!("{} does not have fields.", t)
     }
 }
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index f70c24c3ccb..c7f21427a0c 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -827,7 +827,9 @@ pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef {
         }
     }
     DebugLoc::None.apply(cx.fcx);
-    Alloca(cx, ty, name)
+    let result = Alloca(cx, ty, name);
+    debug!("alloca({:?}) = {:?}", name, result);
+    result
 }
 
 impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
@@ -1868,7 +1870,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         match **layout {
             Layout::StructWrappedNullablePointer { nonnull: ref variant_layout,
                                                    nndiscr,
-                                                   discrfield: _ } => {
+                                                   discrfield: _,
+                                                   discrfield_source: _ } => {
                 debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}",
                        ty, nndiscr, variant_layout);
                 let variant_def = &adt_def.variants[nndiscr as usize];
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index bc9c86c99a3..511c9d3c13f 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -870,25 +870,28 @@ impl<'tcx> MemberDescriptionFactory<'tcx> {
 
 // Creates MemberDescriptions for the fields of a struct
 struct StructMemberDescriptionFactory<'tcx> {
+    ty: Ty<'tcx>,
     variant: &'tcx ty::VariantDef,
     substs: &'tcx Substs<'tcx>,
-    is_simd: bool,
     span: Span,
 }
 
 impl<'tcx> StructMemberDescriptionFactory<'tcx> {
     fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
                                       -> Vec<MemberDescription> {
-        let field_size = if self.is_simd {
-            let fty = monomorphize::field_ty(cx.tcx(),
-                                             self.substs,
-                                             &self.variant.fields[0]);
-            Some(machine::llsize_of_alloc(
-                cx,
-                type_of::type_of(cx, fty)
-            ) as usize)
-        } else {
-            None
+        let layout = cx.layout_of(self.ty);
+
+        let tmp;
+        let offsets = match *layout {
+            layout::Univariant { ref variant, .. } => &variant.offsets,
+            layout::Vector { element, count } => {
+                let element_size = element.size(&cx.tcx().data_layout).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)| {
@@ -899,11 +902,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> {
             };
             let fty = monomorphize::field_ty(cx.tcx(), self.substs, f);
 
-            let offset = if self.is_simd {
-                FixedMemberOffset { bytes: i * field_size.unwrap() }
-            } else {
-                ComputedMemberOffset
-            };
+            let offset = FixedMemberOffset { bytes: offsets[i].bytes() as usize};
 
             MemberDescription {
                 name: name,
@@ -945,9 +944,9 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         struct_metadata_stub,
         struct_llvm_type,
         StructMDF(StructMemberDescriptionFactory {
+            ty: struct_type,
             variant: variant,
             substs: substs,
-            is_simd: struct_type.is_simd(),
             span: span,
         })
     )
@@ -959,6 +958,7 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
 // Creates MemberDescriptions for the fields of a tuple
 struct TupleMemberDescriptionFactory<'tcx> {
+    ty: Ty<'tcx>,
     component_types: Vec<Ty<'tcx>>,
     span: Span,
 }
@@ -966,6 +966,13 @@ struct TupleMemberDescriptionFactory<'tcx> {
 impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
     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 {
+            &variant.offsets
+        } else {
+            bug!("{} is not a tuple", self.ty);
+        };
+
         self.component_types
             .iter()
             .enumerate()
@@ -974,7 +981,7 @@ impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
                 name: format!("__{}", i),
                 llvm_type: type_of::type_of(cx, component_type),
                 type_metadata: type_metadata(cx, component_type, self.span),
-                offset: ComputedMemberOffset,
+                offset: FixedMemberOffset { bytes: offsets[i].bytes() as usize },
                 flags: DIFlags::FlagZero,
             }
         }).collect()
@@ -1001,6 +1008,7 @@ fn prepare_tuple_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                            NO_SCOPE_METADATA),
         tuple_llvm_type,
         TupleMDF(TupleMemberDescriptionFactory {
+            ty: tuple_type,
             component_types: component_types.to_vec(),
             span: span,
         })
@@ -1239,7 +1247,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
             },
             layout::StructWrappedNullablePointer { nonnull: ref struct_def,
                                                 nndiscr,
-                                                ref discrfield, ..} => {
+                                                ref discrfield_source, ..} => {
                 // Create a description of the non-null variant
                 let (variant_type_metadata, variant_llvm_type, member_description_factory) =
                     describe_enum_variant(cx,
@@ -1262,12 +1270,12 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
                 // member's name.
                 let null_variant_index = (1 - nndiscr) as usize;
                 let null_variant_name = adt.variants[null_variant_index].name;
-                let discrfield = discrfield.iter()
+                let discrfield_source = discrfield_source.iter()
                                            .skip(1)
                                            .map(|x| x.to_string())
                                            .collect::<Vec<_>>().join("$");
                 let union_member_name = format!("RUST$ENCODED$ENUM${}${}",
-                                                discrfield,
+                                                discrfield_source,
                                                 null_variant_name);
 
                 // Create the (singleton) list of descriptions of union members.
@@ -1289,6 +1297,8 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
 
 // Creates MemberDescriptions for the fields of a single enum variant.
 struct VariantMemberDescriptionFactory<'tcx> {
+    // Cloned from the layout::Struct describing the variant.
+    offsets: &'tcx [layout::Size],
     args: Vec<(String, Ty<'tcx>)>,
     discriminant_type_metadata: Option<DIType>,
     span: Span,
@@ -1305,7 +1315,7 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
                     Some(metadata) if i == 0 => metadata,
                     _ => type_metadata(cx, ty, self.span)
                 },
-                offset: ComputedMemberOffset,
+                offset: FixedMemberOffset { bytes: self.offsets[i].bytes() as usize },
                 flags: DIFlags::FlagZero
             }
         }).collect()
@@ -1325,7 +1335,7 @@ enum EnumDiscriminantInfo {
 // full RecursiveTypeDescription.
 fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                    enum_type: Ty<'tcx>,
-                                   struct_def: &layout::Struct,
+                                   struct_def: &'tcx layout::Struct,
                                    variant: &'tcx ty::VariantDef,
                                    discriminant_info: EnumDiscriminantInfo,
                                    containing_scope: DIScope,
@@ -1409,6 +1419,7 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
     let member_description_factory =
         VariantMDF(VariantMemberDescriptionFactory {
+            offsets: &struct_def.offsets[..],
             args: args,
             discriminant_type_metadata: match discriminant_info {
                 RegularDiscriminant(discriminant_type_metadata) => {
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 76f5f32b5dc..fe087bc4951 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -11,7 +11,7 @@
 use llvm::{self, ValueRef};
 use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
 use rustc::middle::lang_items;
-use rustc::ty;
+use rustc::ty::{self, layout};
 use rustc::mir;
 use abi::{Abi, FnType, ArgType};
 use adt;
@@ -722,8 +722,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
             }
             Immediate(llval) => {
+                let l = bcx.ccx().layout_of(tuple.ty);
+                let v = if let layout::Univariant { ref variant, .. } = *l {
+                    variant
+                } else {
+                    bug!("Not a tuple.");
+                };
                 for (n, &ty) in arg_types.iter().enumerate() {
-                    let mut elem = bcx.extract_value(llval, n);
+                    let mut elem = bcx.extract_value(llval, v.memory_index[n] as usize);
                     // Truncate bools to i1, if needed
                     if ty.is_bool() && common::val_ty(elem) != Type::i1(bcx.ccx()) {
                         elem = bcx.trunc(elem, Type::i1(bcx.ccx()));
diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs
index 62eda56e2e1..83e1d03c689 100644
--- a/src/librustc_trans/mir/operand.rs
+++ b/src/librustc_trans/mir/operand.rs
@@ -246,7 +246,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                          lldest: ValueRef,
                          operand: OperandRef<'tcx>)
     {
-        debug!("store_operand: operand={:?}", operand);
+        debug!("store_operand: operand={:?} lldest={:?}", operand, lldest);
         bcx.with_block(|bcx| self.store_operand_direct(bcx, lldest, operand))
     }
 
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 15cbbc720d6..2ee49db4778 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -133,6 +133,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         }
                     },
                     _ => {
+                        // If this is a tuple or closure, we need to translate GEP indices.
+                        let layout = bcx.ccx().layout_of(dest.ty.to_ty(bcx.tcx()));
+                        let translation = if let Layout::Univariant { ref variant, .. } = *layout {
+                            Some(&variant.memory_index)
+                        } else {
+                            None
+                        };
                         for (i, operand) in operands.iter().enumerate() {
                             let op = self.trans_operand(&bcx, operand);
                             // Do not generate stores and GEPis for zero-sized fields.
@@ -140,6 +147,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                 // Note: perhaps this should be StructGep, but
                                 // note that in some cases the values here will
                                 // not be structs but arrays.
+                                let i = if let Some(ref t) = translation {
+                                    t[i] as usize
+                                } else {
+                                    i
+                                };
                                 let dest = bcx.gepi(dest.llval, &[0, i]);
                                 self.store_operand(&bcx, dest, op);
                             }
diff --git a/src/test/debuginfo/borrowed-enum.rs b/src/test/debuginfo/borrowed-enum.rs
index ddc29c64302..f34fc3b20d2 100644
--- a/src/test/debuginfo/borrowed-enum.rs
+++ b/src/test/debuginfo/borrowed-enum.rs
@@ -18,11 +18,11 @@
 // gdb-command:run
 
 // gdb-command:print *the_a_ref
-// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
 // gdbr-check:$1 = borrowed_enum::ABC::TheA{x: 0, y: 8970181431921507452}
 
 // gdb-command:print *the_b_ref
-// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
 // gdbr-check:$2 = borrowed_enum::ABC::TheB(0, 286331153, 286331153)
 
 // gdb-command:print *univariant_ref
diff --git a/src/test/debuginfo/by-value-non-immediate-argument.rs b/src/test/debuginfo/by-value-non-immediate-argument.rs
index 6d821dbc155..0fe08c3a227 100644
--- a/src/test/debuginfo/by-value-non-immediate-argument.rs
+++ b/src/test/debuginfo/by-value-non-immediate-argument.rs
@@ -42,7 +42,7 @@
 // gdb-command:continue
 
 // gdb-command:print x
-// gdbg-check:$7 = {{RUST$ENUM$DISR = Case1, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}}
+// gdbg-check:$7 = {{RUST$ENUM$DISR = Case1, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$7 = by_value_non_immediate_argument::Enum::Case1{x: 0, y: 8970181431921507452}
 // gdb-command:continue
 
diff --git a/src/test/debuginfo/generic-struct-style-enum.rs b/src/test/debuginfo/generic-struct-style-enum.rs
index dba9422721a..a328eec6893 100644
--- a/src/test/debuginfo/generic-struct-style-enum.rs
+++ b/src/test/debuginfo/generic-struct-style-enum.rs
@@ -17,15 +17,15 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$1 = generic_struct_style_enum::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868}
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
 // gdbr-check:$2 = generic_struct_style_enum::Regular::Case2{a: 0, b: 286331153, c: 286331153}
 
 // gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
+// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
 // gdbr-check:$3 = generic_struct_style_enum::Regular::Case3{a: 0, b: 6438275382588823897}
 
 // gdb-command:print univariant
diff --git a/src/test/debuginfo/generic-tuple-style-enum.rs b/src/test/debuginfo/generic-tuple-style-enum.rs
index 01d2ff4e334..9ada5fdeff7 100644
--- a/src/test/debuginfo/generic-tuple-style-enum.rs
+++ b/src/test/debuginfo/generic-tuple-style-enum.rs
@@ -19,15 +19,15 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$1 = generic_tuple_style_enum::Regular::Case1(0, 31868, 31868, 31868, 31868)
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = 4369, __2 = 4369, __3 = 4369, __4 = 4369}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
 // gdbr-check:$2 = generic_tuple_style_enum::Regular::Case2(0, 286331153, 286331153)
 
 // gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, __0 = 0, __1 = 22873, __2 = 22873, __3 = 22873, __4 = 22873}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 1499027801, __2 = 1499027801}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
+// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
 // gdbr-check:$3 = generic_tuple_style_enum::Regular::Case3(0, 6438275382588823897)
 
 // gdb-command:print univariant
diff --git a/src/test/debuginfo/struct-in-enum.rs b/src/test/debuginfo/struct-in-enum.rs
index d0aceaa4f3f..ffd36ae14ad 100644
--- a/src/test/debuginfo/struct-in-enum.rs
+++ b/src/test/debuginfo/struct-in-enum.rs
@@ -19,11 +19,11 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = {x = 2088533116, y = 2088533116, z = 31868}}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452, __2 = 31868}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = {x = 2088533116, y = 2088533116, z = 31868}}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$1 = struct_in_enum::Regular::Case1(0, struct_in_enum::Struct {x: 2088533116, y: 2088533116, z: 31868})
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = {x = 286331153, y = 286331153, z = 4369}}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441, __2 = 4369}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441, __2 = 4369}}
 // gdbr-check:$2 = struct_in_enum::Regular::Case2(0, 1229782938247303441, 4369)
 
 // gdb-command:print univariant
diff --git a/src/test/debuginfo/struct-style-enum.rs b/src/test/debuginfo/struct-style-enum.rs
index 8abc139eb11..b6196daaa46 100644
--- a/src/test/debuginfo/struct-style-enum.rs
+++ b/src/test/debuginfo/struct-style-enum.rs
@@ -19,15 +19,15 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$1 = struct_style_enum::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868}
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
 // gdbr-check:$2 = struct_style_enum::Regular::Case2{a: 0, b: 286331153, c: 286331153}
 
 // gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
+// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
 // gdbr-check:$3 = struct_style_enum::Regular::Case3{a: 0, b: 6438275382588823897}
 
 // gdb-command:print univariant
diff --git a/src/test/debuginfo/tuple-style-enum.rs b/src/test/debuginfo/tuple-style-enum.rs
index d05edec3e73..988f223b3bc 100644
--- a/src/test/debuginfo/tuple-style-enum.rs
+++ b/src/test/debuginfo/tuple-style-enum.rs
@@ -19,15 +19,15 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$1 = tuple_style_enum::Regular::Case1(0, 31868, 31868, 31868, 31868)
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = 4369, __2 = 4369, __3 = 4369, __4 = 4369}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
 // gdbr-check:$2 = tuple_style_enum::Regular::Case2(0, 286331153, 286331153)
 
 // gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, __0 = 0, __1 = 22873, __2 = 22873, __3 = 22873, __4 = 22873}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 1499027801, __2 = 1499027801}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
+// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
 // gdbr-check:$3 = tuple_style_enum::Regular::Case3(0, 6438275382588823897)
 
 // gdb-command:print univariant
diff --git a/src/test/debuginfo/unique-enum.rs b/src/test/debuginfo/unique-enum.rs
index e882544b802..cf8d90e30f1 100644
--- a/src/test/debuginfo/unique-enum.rs
+++ b/src/test/debuginfo/unique-enum.rs
@@ -18,11 +18,11 @@
 // gdb-command:run
 
 // gdb-command:print *the_a
-// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
 // gdbr-check:$1 = unique_enum::ABC::TheA{x: 0, y: 8970181431921507452}
 
 // gdb-command:print *the_b
-// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
 // gdbr-check:$2 = unique_enum::ABC::TheB(0, 286331153, 286331153)
 
 // gdb-command:print *univariant
diff --git a/src/test/run-pass/closure-immediate.rs b/src/test/run-pass/closure-immediate.rs
new file mode 100644
index 00000000000..e566c105835
--- /dev/null
+++ b/src/test/run-pass/closure-immediate.rs
@@ -0,0 +1,22 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+// After the work to reoptimize structs, it became possible for immediate logic to fail.
+// This test verifies that it actually works.
+
+fn main() {
+    let c = |a: u8, b: u16, c: u8| {
+        assert_eq!(a, 1);
+        assert_eq!(b, 2);
+        assert_eq!(c, 3);
+    };
+    c(1, 2, 3);
+}
diff --git a/src/test/run-pass/enum-size-variance.rs b/src/test/run-pass/enum-size-variance.rs
index 26deb0ed72a..a3e95a15341 100644
--- a/src/test/run-pass/enum-size-variance.rs
+++ b/src/test/run-pass/enum-size-variance.rs
@@ -11,6 +11,9 @@
 #![warn(variant_size_differences)]
 #![allow(dead_code)]
 
+// Note that the following test works because all fields of the enum variants are of the same size.
+// If this test is modified and the reordering logic in librustc/ty/layout.rs kicks in, it fails.
+
 enum Enum1 { }
 
 enum Enum2 { A, B, C }
diff --git a/src/test/run-pass/extern-pass-empty.rs b/src/test/run-pass/extern-pass-empty.rs
index cce7dc5bf32..2606c928680 100644
--- a/src/test/run-pass/extern-pass-empty.rs
+++ b/src/test/run-pass/extern-pass-empty.rs
@@ -14,11 +14,13 @@
 // ignore-msvc
 // ignore-emscripten
 
+#[repr(C)]
 struct TwoU8s {
     one: u8,
     two: u8,
 }
 
+#[repr(C)]
 struct ManyInts {
     arg1: i8,
     arg2: i16,
@@ -28,6 +30,7 @@ struct ManyInts {
     arg6: TwoU8s,
 }
 
+#[repr(C)]
 struct Empty;
 
 #[link(name = "rust_test_helpers", kind = "static")]
diff --git a/src/test/run-pass/multiple-reprs.rs b/src/test/run-pass/multiple-reprs.rs
new file mode 100644
index 00000000000..c2fe943eed8
--- /dev/null
+++ b/src/test/run-pass/multiple-reprs.rs
@@ -0,0 +1,43 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+use std::mem::size_of;
+
+// The two enums that follow are designed so that bugs trigger layout optimization.
+// Specifically, if either of the following reprs used here is not detected by the compiler,
+// then the sizes will be wrong.
+
+#[repr(C, u8)]
+enum E1 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+#[repr(u8, C)]
+enum E2 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+// From pr 37429
+
+#[repr(C,packed)]
+pub struct p0f_api_query {
+    pub magic: u32,
+    pub addr_type: u8,
+    pub addr: [u8; 16],
+}
+
+pub fn main() {
+    assert_eq!(size_of::<E1>(), 6);
+    assert_eq!(size_of::<E2>(), 6);
+    assert_eq!(size_of::<p0f_api_query>(), 21);
+}
diff --git a/src/test/run-pass/nonzero-enum.rs b/src/test/run-pass/nonzero-enum.rs
index 266506e04b7..fc92c9df9f7 100644
--- a/src/test/run-pass/nonzero-enum.rs
+++ b/src/test/run-pass/nonzero-enum.rs
@@ -26,8 +26,7 @@ fn main() {
     assert_eq!(size_of::<E>(), 1);
     assert_eq!(size_of::<Option<E>>(), 1);
     assert_eq!(size_of::<Result<E, ()>>(), 1);
-    assert_eq!(size_of::<S>(), 4);
-    assert_eq!(size_of::<Option<S>>(), 4);
+    assert_eq!(size_of::<Option<S>>(), size_of::<S>());
     let enone = None::<E>;
     let esome = Some(E::A);
     if let Some(..) = enone {
diff --git a/src/test/run-pass/struct-return.rs b/src/test/run-pass/struct-return.rs
index 3d4601ad0cf..ed618cea98a 100644
--- a/src/test/run-pass/struct-return.rs
+++ b/src/test/run-pass/struct-return.rs
@@ -9,9 +9,11 @@
 // except according to those terms.
 //
 
+#[repr(C)]
 #[derive(Copy, Clone)]
 pub struct Quad { a: u64, b: u64, c: u64, d: u64 }
 
+#[repr(C)]
 #[derive(Copy, Clone)]
 pub struct Floats { a: f64, b: u8, c: f64 }
 
diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs
index 86159ce340b..6614a76107f 100644
--- a/src/test/run-pass/type-sizes.rs
+++ b/src/test/run-pass/type-sizes.rs
@@ -26,10 +26,15 @@ enum e2 {
     a(u32), b
 }
 
+#[repr(C, u8)]
 enum e3 {
     a([u16; 0], u8), b
 }
 
+// Test struct field reordering to make sure it actually reorders.
+struct WillOptimize1(u8, u16, u8);
+struct WillOptimize2 { a: u8, b: u16, c: u8}
+
 pub fn main() {
     assert_eq!(size_of::<u8>(), 1 as usize);
     assert_eq!(size_of::<u32>(), 4 as usize);
@@ -53,4 +58,7 @@ pub fn main() {
     assert_eq!(size_of::<e1>(), 8 as usize);
     assert_eq!(size_of::<e2>(), 8 as usize);
     assert_eq!(size_of::<e3>(), 4 as usize);
+
+    assert_eq!(size_of::<WillOptimize1>(), 4);
+    assert_eq!(size_of::<WillOptimize2>(), 4);
 }
diff --git a/src/test/ui/print_type_sizes/nullable.stdout b/src/test/ui/print_type_sizes/nullable.stdout
index dd999c4a5e4..830678f174f 100644
--- a/src/test/ui/print_type_sizes/nullable.stdout
+++ b/src/test/ui/print_type_sizes/nullable.stdout
@@ -1,25 +1,22 @@
-print-type-size type: `IndirectNonZero<u32>`: 20 bytes, alignment: 4 bytes
-print-type-size     field `.pre`: 1 bytes
-print-type-size     padding: 3 bytes
-print-type-size     field `.nested`: 12 bytes, alignment: 4 bytes
+print-type-size type: `IndirectNonZero<u32>`: 12 bytes, alignment: 4 bytes
+print-type-size     field `.nested`: 8 bytes
 print-type-size     field `.post`: 2 bytes
-print-type-size     end padding: 2 bytes
-print-type-size type: `MyOption<IndirectNonZero<u32>>`: 20 bytes, alignment: 4 bytes
-print-type-size     variant `Some`: 20 bytes
-print-type-size         field `.0`: 20 bytes
-print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes
-print-type-size     variant `Record`: 10 bytes
-print-type-size         field `.pre`: 1 bytes
-print-type-size         padding: 3 bytes
-print-type-size         field `.val`: 4 bytes, alignment: 4 bytes
-print-type-size         field `.post`: 2 bytes
-print-type-size     end padding: 2 bytes
-print-type-size type: `NestedNonZero<u32>`: 12 bytes, alignment: 4 bytes
 print-type-size     field `.pre`: 1 bytes
-print-type-size     padding: 3 bytes
-print-type-size     field `.val`: 4 bytes, alignment: 4 bytes
+print-type-size     end padding: 1 bytes
+print-type-size type: `MyOption<IndirectNonZero<u32>>`: 12 bytes, alignment: 4 bytes
+print-type-size     variant `Some`: 12 bytes
+print-type-size         field `.0`: 12 bytes
+print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
+print-type-size     variant `Record`: 7 bytes
+print-type-size         field `.val`: 4 bytes
+print-type-size         field `.post`: 2 bytes
+print-type-size         field `.pre`: 1 bytes
+print-type-size     end padding: 1 bytes
+print-type-size type: `NestedNonZero<u32>`: 8 bytes, alignment: 4 bytes
+print-type-size     field `.val`: 4 bytes
 print-type-size     field `.post`: 2 bytes
-print-type-size     end padding: 2 bytes
+print-type-size     field `.pre`: 1 bytes
+print-type-size     end padding: 1 bytes
 print-type-size type: `MyOption<core::nonzero::NonZero<u32>>`: 4 bytes, alignment: 4 bytes
 print-type-size     variant `Some`: 4 bytes
 print-type-size         field `.0`: 4 bytes
diff --git a/src/test/ui/print_type_sizes/packed.stdout b/src/test/ui/print_type_sizes/packed.stdout
index 1278a7d7c92..83fd333c9c7 100644
--- a/src/test/ui/print_type_sizes/packed.stdout
+++ b/src/test/ui/print_type_sizes/packed.stdout
@@ -1,13 +1,11 @@
-print-type-size type: `Padded`: 16 bytes, alignment: 4 bytes
+print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes
+print-type-size     field `.g`: 4 bytes
+print-type-size     field `.h`: 2 bytes
 print-type-size     field `.a`: 1 bytes
 print-type-size     field `.b`: 1 bytes
-print-type-size     padding: 2 bytes
-print-type-size     field `.g`: 4 bytes, alignment: 4 bytes
 print-type-size     field `.c`: 1 bytes
-print-type-size     padding: 1 bytes
-print-type-size     field `.h`: 2 bytes, alignment: 2 bytes
 print-type-size     field `.d`: 1 bytes
-print-type-size     end padding: 3 bytes
+print-type-size     end padding: 2 bytes
 print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes
 print-type-size     field `.a`: 1 bytes
 print-type-size     field `.b`: 1 bytes
diff --git a/src/test/ui/print_type_sizes/padding.stdout b/src/test/ui/print_type_sizes/padding.stdout
index bb95f790bd9..0eaff7118b3 100644
--- a/src/test/ui/print_type_sizes/padding.stdout
+++ b/src/test/ui/print_type_sizes/padding.stdout
@@ -1,10 +1,12 @@
 print-type-size type: `E1`: 12 bytes, alignment: 4 bytes
-print-type-size     discriminant: 4 bytes
-print-type-size     variant `A`: 5 bytes
-print-type-size         field `.0`: 4 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `A`: 7 bytes
 print-type-size         field `.1`: 1 bytes
-print-type-size     variant `B`: 8 bytes
-print-type-size         field `.0`: 8 bytes
+print-type-size         padding: 2 bytes
+print-type-size         field `.0`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `B`: 11 bytes
+print-type-size         padding: 3 bytes
+print-type-size         field `.0`: 8 bytes, alignment: 4 bytes
 print-type-size type: `E2`: 12 bytes, alignment: 4 bytes
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `A`: 7 bytes
@@ -15,7 +17,7 @@ print-type-size     variant `B`: 11 bytes
 print-type-size         padding: 3 bytes
 print-type-size         field `.0`: 8 bytes, alignment: 4 bytes
 print-type-size type: `S`: 8 bytes, alignment: 4 bytes
+print-type-size     field `.g`: 4 bytes
 print-type-size     field `.a`: 1 bytes
 print-type-size     field `.b`: 1 bytes
-print-type-size     padding: 2 bytes
-print-type-size     field `.g`: 4 bytes, alignment: 4 bytes
+print-type-size     end padding: 2 bytes