about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/ty/context.rs6
-rw-r--r--src/librustc/ty/layout.rs63
-rw-r--r--src/librustc_mir/interpret/const_eval.rs19
-rw-r--r--src/librustc_mir/interpret/eval_context.rs71
-rw-r--r--src/librustc_mir/interpret/place.rs27
-rw-r--r--src/librustc_mir/interpret/step.rs18
-rw-r--r--src/librustc_trans/glue.rs9
-rw-r--r--src/librustc_trans/mir/constant.rs17
-rw-r--r--src/librustc_trans/mir/place.rs42
-rw-r--r--src/librustc_trans/type_of.rs28
10 files changed, 116 insertions, 184 deletions
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 9ebdd592922..5464fa601ec 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -895,7 +895,7 @@ pub struct InterpretInterner<'tcx> {
     /// Allows checking whether a constant already has an allocation
     ///
     /// The pointers are to the beginning of an `alloc_by_id` allocation
-    alloc_cache: FxHashMap<interpret::GlobalId<'tcx>, interpret::PtrAndAlign>,
+    alloc_cache: FxHashMap<interpret::GlobalId<'tcx>, interpret::Pointer>,
 
     /// A cache for basic byte allocations keyed by their contents. This is used to deduplicate
     /// allocations for string and bytestring literals.
@@ -931,14 +931,14 @@ impl<'tcx> InterpretInterner<'tcx> {
     pub fn get_cached(
         &self,
         global_id: interpret::GlobalId<'tcx>,
-    ) -> Option<interpret::PtrAndAlign> {
+    ) -> Option<interpret::Pointer> {
         self.alloc_cache.get(&global_id).cloned()
     }
 
     pub fn cache(
         &mut self,
         global_id: interpret::GlobalId<'tcx>,
-        ptr: interpret::PtrAndAlign,
+        ptr: interpret::Pointer,
     ) {
         if let Some(old) = self.alloc_cache.insert(global_id, ptr) {
             bug!("tried to cache {:?}, but was already existing as {:#?}", global_id, old);
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index fe96cb083f5..42987e3dd78 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -778,7 +778,6 @@ pub enum Abi {
     Aggregate {
         /// If true, the size is exact, otherwise it's only a lower bound.
         sized: bool,
-        packed: bool
     }
 }
 
@@ -790,18 +789,7 @@ impl Abi {
             Abi::Scalar(_) |
             Abi::ScalarPair(..) |
             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::Uninhabited |
-            Abi::Scalar(_) |
-            Abi::ScalarPair(..) |
-            Abi::Vector { .. } => false,
-            Abi::Aggregate { packed, .. } => packed
+            Abi::Aggregate { sized } => !sized
         }
     }
 }
@@ -1077,10 +1065,7 @@ impl<'a, 'tcx> LayoutDetails {
             }
 
             let size = min_size.abi_align(align);
-            let mut abi = Abi::Aggregate {
-                sized,
-                packed
-            };
+            let mut abi = Abi::Aggregate { sized };
 
             // Unpack newtype ABIs and find scalar pairs.
             if sized && size.bytes() > 0 {
@@ -1254,10 +1239,7 @@ impl<'a, 'tcx> LayoutDetails {
                         stride: element.size,
                         count
                     },
-                    abi: Abi::Aggregate {
-                        sized: true,
-                        packed: false
-                    },
+                    abi: Abi::Aggregate { sized: true },
                     align: element.align,
                     size
                 })
@@ -1270,10 +1252,7 @@ impl<'a, 'tcx> LayoutDetails {
                         stride: element.size,
                         count: 0
                     },
-                    abi: Abi::Aggregate {
-                        sized: false,
-                        packed: false
-                    },
+                    abi: Abi::Aggregate { sized: false },
                     align: element.align,
                     size: Size::from_bytes(0)
                 })
@@ -1285,10 +1264,7 @@ impl<'a, 'tcx> LayoutDetails {
                         stride: Size::from_bytes(1),
                         count: 0
                     },
-                    abi: Abi::Aggregate {
-                        sized: false,
-                        packed: false
-                    },
+                    abi: Abi::Aggregate { sized: false },
                     align: dl.i8_align,
                     size: Size::from_bytes(0)
                 })
@@ -1302,7 +1278,7 @@ impl<'a, 'tcx> LayoutDetails {
                 let mut unit = univariant_uninterned(&[], &ReprOptions::default(),
                   StructKind::AlwaysSized)?;
                 match unit.abi {
-                    Abi::Aggregate { ref mut sized, .. } => *sized = false,
+                    Abi::Aggregate { ref mut sized } => *sized = false,
                     _ => bug!()
                 }
                 tcx.intern_layout(unit)
@@ -1418,10 +1394,7 @@ impl<'a, 'tcx> LayoutDetails {
                     return Ok(tcx.intern_layout(LayoutDetails {
                         variants: Variants::Single { index: 0 },
                         fields: FieldPlacement::Union(variants[0].len()),
-                        abi: Abi::Aggregate {
-                            sized: true,
-                            packed
-                        },
+                        abi: Abi::Aggregate { sized: true },
                         align,
                         size: size.abi_align(align)
                     }));
@@ -1525,15 +1498,10 @@ impl<'a, 'tcx> LayoutDetails {
                             let abi = if offset.bytes() == 0 && niche.value.size(dl) == size {
                                 Abi::Scalar(niche.clone())
                             } else {
-                                let mut packed = st[i].abi.is_packed();
                                 if offset.abi_align(niche_align) != offset {
-                                    packed = true;
                                     niche_align = dl.i8_align;
                                 }
-                                Abi::Aggregate {
-                                    sized: true,
-                                    packed
-                                }
+                                Abi::Aggregate { sized: true }
                             };
                             align = align.max(niche_align);
 
@@ -1681,10 +1649,7 @@ impl<'a, 'tcx> LayoutDetails {
                 let abi = if discr.value.size(dl) == size {
                     Abi::Scalar(discr.clone())
                 } else {
-                    Abi::Aggregate {
-                        sized: true,
-                        packed: false
-                    }
+                    Abi::Aggregate { sized: true }
                 };
                 tcx.intern_layout(LayoutDetails {
                     variants: Variants::Tagged {
@@ -2277,11 +2242,6 @@ impl<'a, 'tcx> TyLayout<'tcx> {
         self.abi.is_unsized()
     }
 
-    /// Returns true if the fields of the layout are packed.
-    pub fn is_packed(&self) -> bool {
-        self.abi.is_packed()
-    }
-
     /// Returns true if the type is a ZST and not unsized.
     pub fn is_zst(&self) -> bool {
         match self.abi {
@@ -2289,7 +2249,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
             Abi::Scalar(_) |
             Abi::ScalarPair(..) |
             Abi::Vector { .. } => false,
-            Abi::Aggregate { sized, .. } => sized && self.size.bytes() == 0
+            Abi::Aggregate { sized } => sized && self.size.bytes() == 0
         }
     }
 
@@ -2452,8 +2412,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
                 element.hash_stable(hcx, hasher);
                 count.hash_stable(hcx, hasher);
             }
-            Aggregate { packed, sized } => {
-                packed.hash_stable(hcx, hasher);
+            Aggregate { sized } => {
                 sized.hash_stable(hcx, hasher);
             }
         }
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs
index fc4d1d98941..aaadddba0c1 100644
--- a/src/librustc_mir/interpret/const_eval.rs
+++ b/src/librustc_mir/interpret/const_eval.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::indexed_vec::Idx;
 use syntax::ast::Mutability;
 use syntax::codemap::Span;
 
-use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, PrimVal, PtrAndAlign};
+use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, Pointer, PrimVal, PtrAndAlign};
 use super::{Place, PlaceExtra, EvalContext, StackPopCleanup, ValTy, HasMemory};
 
 use rustc_const_math::ConstInt;
@@ -45,7 +45,7 @@ pub fn eval_body<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     instance: Instance<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-) -> EvalResult<'tcx, (PtrAndAlign, Ty<'tcx>)> {
+) -> EvalResult<'tcx, (Pointer, Ty<'tcx>)> {
     debug!("eval_body: {:?}, {:?}", instance, param_env);
     let limits = super::ResourceLimits::default();
     let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ());
@@ -69,13 +69,7 @@ pub fn eval_body<'a, 'tcx>(
             layout.align.abi(),
             None,
         )?;
-        tcx.interpret_interner.borrow_mut().cache(
-            cid,
-            PtrAndAlign {
-                ptr: ptr.into(),
-                aligned: !layout.is_packed(),
-            },
-        );
+        tcx.interpret_interner.borrow_mut().cache(cid, ptr.into());
         let cleanup = StackPopCleanup::MarkStatic(Mutability::Immutable);
         let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id()));
         trace!("const_eval: pushing stack frame for global: {}", name);
@@ -101,7 +95,7 @@ pub fn eval_body_as_integer<'a, 'tcx>(
     let ptr_ty = eval_body(tcx, instance, param_env);
     let (ptr, ty) = ptr_ty?;
     let ecx = mk_eval_cx(tcx, instance, param_env)?;
-    let prim = match ecx.read_maybe_aligned(ptr.aligned, |ectx| ectx.try_read_value(ptr.ptr, ty))? {
+    let prim = match ecx.try_read_value(ptr, ty)? {
         Some(Value::ByVal(prim)) => prim.to_bytes()?,
         _ => return err!(TypeNotPrimitive(ty)),
     };
@@ -363,7 +357,10 @@ pub fn const_eval_provider<'a, 'tcx>(
             (_, Err(err)) => Err(err),
             (Ok((miri_val, miri_ty)), Ok(ctfe)) => {
                 let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
-                check_ctfe_against_miri(&mut ecx, miri_val, miri_ty, ctfe.val);
+                check_ctfe_against_miri(&mut ecx, PtrAndAlign {
+                    ptr: miri_val,
+                    aligned: true
+                }, miri_ty, ctfe.val);
                 Ok(ctfe)
             }
         }
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 6b33fd246da..5fe1d6cd540 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -261,11 +261,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
             Unevaluated(def_id, substs) => {
                 let instance = self.resolve(def_id, substs)?;
-                let cid = GlobalId {
+                return Ok(self.read_global_as_value(GlobalId {
                     instance,
                     promoted: None,
-                };
-                return Ok(Value::ByRef(self.tcx.interpret_interner.borrow().get_cached(cid).expect("static/const not cached")));
+                }));
             }
 
             Aggregate(..) |
@@ -834,11 +833,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                     Literal::Value { ref value } => self.const_to_value(&value.val)?,
 
                     Literal::Promoted { index } => {
-                        let cid = GlobalId {
+                        self.read_global_as_value(GlobalId {
                             instance: self.frame().instance,
                             promoted: Some(index),
-                        };
-                        Value::ByRef(self.tcx.interpret_interner.borrow().get_cached(cid).expect("promoted not cached"))
+                        })
                     }
                 };
 
@@ -951,7 +949,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
     }
 
     pub fn read_global_as_value(&self, gid: GlobalId) -> Value {
-        Value::ByRef(self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached"))
+        Value::ByRef(PtrAndAlign {
+            ptr: self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached"),
+            aligned: true
+        })
     }
 
     fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx> {
@@ -1149,51 +1150,29 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             }
             Value::ByVal(primval) => {
                 let layout = self.layout_of(dest_ty)?;
-                if layout.is_zst() {
-                    assert!(primval.is_undef());
-                    Ok(())
-                } else {
-                    // TODO: Do we need signedness?
-                    self.memory.write_maybe_aligned_mut(!layout.is_packed(), |mem| {
-                        mem.write_primval(dest.to_ptr()?, primval, layout.size.bytes(), false)
-                    })
+                match layout.abi {
+                    layout::Abi::Scalar(_) => {}
+                    _ if primval.is_undef() => {}
+                    _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
                 }
+                // TODO: Do we need signedness?
+                self.memory.write_primval(dest.to_ptr()?, primval, layout.size.bytes(), false)
             }
-            Value::ByValPair(a, b) => {
+            Value::ByValPair(a_val, b_val) => {
                 let ptr = dest.to_ptr()?;
                 let mut layout = self.layout_of(dest_ty)?;
                 trace!("write_value_to_ptr valpair: {:#?}", layout);
-                let mut packed = layout.is_packed();
-                'outer: loop {
-                    for i in 0..layout.fields.count() {
-                        let field = layout.field(&self, i)?;
-                        if layout.fields.offset(i).bytes() == 0 && layout.size == field.size {
-                            layout = field;
-                            packed |= layout.is_packed();
-                            continue 'outer;
-                        }
-                    }
-                    break;
-                }
-                trace!("write_value_to_ptr valpair: {:#?}", layout);
-                assert_eq!(layout.fields.count(), 2);
-                let field_0 = layout.field(&self, 0)?;
-                let field_1 = layout.field(&self, 1)?;
-                trace!("write_value_to_ptr field 0: {:#?}", field_0);
-                trace!("write_value_to_ptr field 1: {:#?}", field_1);
-                assert_eq!(
-                    field_0.is_packed(),
-                    field_1.is_packed(),
-                    "the two fields must agree on being packed"
-                );
-                packed |= field_0.is_packed();
-                let field_0_ptr = ptr.offset(layout.fields.offset(0).bytes(), &self)?.into();
-                let field_1_ptr = ptr.offset(layout.fields.offset(1).bytes(), &self)?.into();
+                let (a, b) = match layout.abi {
+                    layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
+                    _ => bug!("write_value_to_ptr: invalid ByValPair layout: {:#?}", layout)
+                };
+                let (a_size, b_size) = (a.size(&self), b.size(&self));
+                let a_ptr = ptr;
+                let b_offset = a_size.abi_align(b.align(&self));
+                let b_ptr = ptr.offset(b_offset.bytes(), &self)?.into();
                 // TODO: What about signedess?
-                self.memory.write_maybe_aligned_mut(!packed, |mem| {
-                    mem.write_primval(field_0_ptr, a, field_0.size.bytes(), false)?;
-                    mem.write_primval(field_1_ptr, b, field_1.size.bytes(), false)
-                })?;
+                self.memory.write_primval(a_ptr, a_val, a_size.bytes(), false)?;
+                self.memory.write_primval(b_ptr, b_val, b_size.bytes(), false)?;
                 Ok(())
             }
         }
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 0e44b414d7f..7c19c9f3080 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -1,6 +1,6 @@
 use rustc::mir;
 use rustc::ty::{self, Ty};
-use rustc::ty::layout::{LayoutOf, TyLayout};
+use rustc::ty::layout::{self, LayoutOf, TyLayout};
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::mir::interpret::{GlobalId, PtrAndAlign};
 
@@ -106,9 +106,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                     instance,
                     promoted: None,
                 };
-                Ok(Some(Value::ByRef(
-                    self.tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached"),
-                )))
+                Ok(Some(self.read_global_as_value(cid)))
             }
             Projection(ref proj) => self.try_read_place_projection(proj),
         }
@@ -193,7 +191,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                     promoted: None,
                 };
                 Place::Ptr {
-                    ptr: self.tcx.interpret_interner.borrow().get_cached(gid).expect("uncached global"),
+                    ptr: PtrAndAlign {
+                        ptr: self.tcx.interpret_interner.borrow().get_cached(gid).expect("uncached global"),
+                        aligned: true
+                    },
                     extra: PlaceExtra::None,
                 }
             }
@@ -232,15 +233,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         let (base_ptr, base_extra) = match base {
             Place::Ptr { ptr, extra } => (ptr, extra),
             Place::Local { frame, local } => {
-                match self.stack[frame].get_local(local)? {
+                match (&self.stack[frame].get_local(local)?, &base_layout.abi) {
                     // in case the field covers the entire type, just return the value
-                    Value::ByVal(_) if offset.bytes() == 0 &&
-                                       field.size == base_layout.size => {
+                    (&Value::ByVal(_), &layout::Abi::Scalar(_)) |
+                    (&Value::ByValPair(..), &layout::Abi::ScalarPair(..))
+                        if offset.bytes() == 0 && field.size == base_layout.size =>
+                    {
                         return Ok((base, field));
                     }
-                    Value::ByRef { .. } |
-                    Value::ByValPair(..) |
-                    Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(),
+                    _ => self.force_allocation(base)?.to_ptr_extra_aligned(),
                 }
             }
         };
@@ -257,9 +258,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         };
 
         let mut ptr = base_ptr.offset(offset, &self)?;
-        // if we were unaligned, stay unaligned
-        // no matter what we were, if we are packed, we must not be aligned anymore
-        ptr.aligned &= !base_layout.is_packed();
+        ptr.aligned &= base_layout.align.abi() >= field.align.abi();
 
         let extra = if !field.is_unsized() {
             PlaceExtra::None
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 352e151e3a1..ae382bd12cd 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -8,7 +8,7 @@ use rustc::mir;
 use rustc::ty::{self, Instance};
 use rustc::ty::layout::LayoutOf;
 use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::{PtrAndAlign, GlobalId};
+use rustc::mir::interpret::GlobalId;
 
 use rustc::mir::interpret::{EvalResult, EvalErrorKind};
 use super::{EvalContext, StackPopCleanup, Place, Machine};
@@ -182,13 +182,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             layout.align.abi(),
             None,
         )?;
-        self.tcx.interpret_interner.borrow_mut().cache(
-            cid,
-            PtrAndAlign {
-                ptr: ptr.into(),
-                aligned: !layout.is_packed(),
-            },
-        );
+        self.tcx.interpret_interner.borrow_mut().cache(cid, ptr.into());
         let internally_mutable = !layout.ty.is_freeze(self.tcx, self.param_env, span);
         let mutability = if mutability == Mutability::Mutable || internally_mutable {
             Mutability::Mutable
@@ -273,13 +267,7 @@ impl<'a, 'b, 'tcx, M: Machine<'tcx>> Visitor<'tcx> for ConstantExtractor<'a, 'b,
                         layout.align.abi(),
                         None,
                     )?;
-                    this.ecx.tcx.interpret_interner.borrow_mut().cache(
-                        cid,
-                        PtrAndAlign {
-                            ptr: ptr.into(),
-                            aligned: !layout.is_packed(),
-                        },
-                    );
+                    this.ecx.tcx.interpret_interner.borrow_mut().cache(cid, ptr.into());
                     trace!("pushing stack frame for {:?}", index);
                     this.ecx.push_stack_frame(
                         this.instance,
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 6c7d7700ade..9477adc17c0 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -69,7 +69,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
             // Recurse to get the size of the dynamically sized field (must be
             // the last field).
             let field_ty = layout.field(ccx, i).ty;
-            let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
+            let (unsized_size, mut unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
 
             // FIXME (#26403, #27023): We should be adding padding
             // to `sized_size` (to accommodate the `unsized_align`
@@ -81,6 +81,13 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
             // Return the sum of sizes and max of aligns.
             let size = bcx.add(sized_size, unsized_size);
 
+            // Packed types ignore the alignment of their fields.
+            if let ty::TyAdt(def, _) = t.sty {
+                if def.repr.packed() {
+                    unsized_align = sized_align;
+                }
+            }
+
             // Choose max of two known alignments (combined value must
             // be aligned according to more restrictive of the two).
             let align = match (const_to_opt_u128(sized_align, false),
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 5521d842c95..68913c1d6b7 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -1134,12 +1134,14 @@ fn trans_const_adt<'a, 'tcx>(
             if let layout::FieldPlacement::Union(_) = l.fields {
                 assert_eq!(variant_index, 0);
                 assert_eq!(vals.len(), 1);
+                let (field_size, field_align) = ccx.size_and_align_of(vals[0].ty);
                 let contents = [
                     vals[0].llval,
-                    padding(ccx, l.size - ccx.size_of(vals[0].ty))
+                    padding(ccx, l.size - field_size)
                 ];
 
-                Const::new(C_struct(ccx, &contents, l.is_packed()), t)
+                let packed = l.align.abi() < field_align.abi();
+                Const::new(C_struct(ccx, &contents, packed), t)
             } else {
                 if let layout::Abi::Vector { .. } = l.abi {
                     if let layout::FieldPlacement::Array { .. } = l.fields {
@@ -1232,28 +1234,33 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 
     // offset of current value
+    let mut packed = false;
     let mut offset = Size::from_bytes(0);
     let mut cfields = Vec::new();
     cfields.reserve(discr.is_some() as usize + 1 + layout.fields.count() * 2);
 
     if let Some(discr) = discr {
+        let (field_size, field_align) = ccx.size_and_align_of(discr.ty);
+        packed |= layout.align.abi() < field_align.abi();
         cfields.push(discr.llval);
-        offset = ccx.size_of(discr.ty);
+        offset = field_size;
     }
 
     let parts = layout.fields.index_by_increasing_offset().map(|i| {
         (vals[i], layout.fields.offset(i))
     });
     for (val, target_offset) in parts {
+        let (field_size, field_align) = ccx.size_and_align_of(val.ty);
+        packed |= layout.align.abi() < field_align.abi();
         cfields.push(padding(ccx, target_offset - offset));
         cfields.push(val.llval);
-        offset = target_offset + ccx.size_of(val.ty);
+        offset = target_offset + field_size;
     }
 
     // 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, layout.is_packed()), layout.ty)
+    Const::new(C_struct(ccx, &cfields, packed), layout.ty)
 }
 
 fn padding(ccx: &CrateContext, size: Size) -> ValueRef {
diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs
index 806aca54dc0..214686f4ca1 100644
--- a/src/librustc_trans/mir/place.rs
+++ b/src/librustc_trans/mir/place.rs
@@ -55,11 +55,7 @@ impl ops::BitOr for Alignment {
 
 impl<'a> From<TyLayout<'a>> for Alignment {
     fn from(layout: TyLayout) -> Self {
-        if layout.is_packed() {
-            Alignment::Packed(layout.align)
-        } else {
-            Alignment::AbiAligned
-        }
+        Alignment::Packed(layout.align)
     }
 }
 
@@ -232,25 +228,27 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
             }
         };
 
-        // Simple case - we can just GEP the field
-        //   * Packed struct - There is no alignment padding
-        //   * Field is sized - pointer is properly aligned already
-        if self.layout.is_packed() || !field.is_unsized() {
-            return simple();
-        }
-
-        // If the type of the last field is [T], str or a foreign type, then we don't need to do
-        // any adjusments
+        // Simple cases, which don't need DST adjustment:
+        //   * no metadata available - just log the case
+        //   * known alignment - sized types, [T], str or a foreign type
+        //   * packed struct - there is no alignment padding
         match field.ty.sty {
+            _ if !self.has_extra() => {
+                debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
+                    ix, Value(self.llval));
+                return simple();
+            }
+            _ if !field.is_unsized() => return simple(),
             ty::TySlice(..) | ty::TyStr | ty::TyForeign(..) => return simple(),
-            _ => ()
-        }
-
-        // There's no metadata available, log the case and just do the GEP.
-        if !self.has_extra() {
-            debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
-                ix, Value(self.llval));
-            return simple();
+            ty::TyAdt(def, _) => {
+                if def.repr.packed() {
+                    // FIXME(eddyb) generalize the adjustment when we
+                    // start supporting packing to larger alignments.
+                    assert_eq!(self.layout.align.abi(), 1);
+                    return simple();
+                }
+            }
+            _ => {}
         }
 
         // We need to get the pointer manually now.
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index e432cec3d5e..8d9bc07fe56 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -79,13 +79,14 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     match layout.fields {
         layout::FieldPlacement::Union(_) => {
             let fill = Type::padding_filler(ccx, layout.size, layout.align);
+            let packed = false;
             match name {
                 None => {
-                    Type::struct_(ccx, &[fill], layout.is_packed())
+                    Type::struct_(ccx, &[fill], packed)
                 }
                 Some(ref name) => {
                     let mut llty = Type::named_struct(ccx, name);
-                    llty.set_struct_body(&[fill], layout.is_packed());
+                    llty.set_struct_body(&[fill], packed);
                     llty
                 }
             }
@@ -96,7 +97,8 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         layout::FieldPlacement::Arbitrary { .. } => {
             match name {
                 None => {
-                    Type::struct_(ccx, &struct_llfields(ccx, layout), layout.is_packed())
+                    let (llfields, packed) = struct_llfields(ccx, layout);
+                    Type::struct_(ccx, &llfields, packed)
                 }
                 Some(ref name) => {
                     let llty = Type::named_struct(ccx, name);
@@ -109,15 +111,19 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 }
 
 fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                             layout: TyLayout<'tcx>) -> Vec<Type> {
+                             layout: TyLayout<'tcx>)
+                             -> (Vec<Type>, bool) {
     debug!("struct_llfields: {:#?}", layout);
     let field_count = layout.fields.count();
 
+    let mut packed = false;
     let mut offset = Size::from_bytes(0);
     let mut prev_align = layout.align;
     let mut result: Vec<Type> = Vec::with_capacity(1 + field_count * 2);
     for i in layout.fields.index_by_increasing_offset() {
         let field = layout.field(ccx, i);
+        packed |= layout.align.abi() < field.align.abi();
+
         let target_offset = layout.fields.offset(i as usize);
         debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?}",
             i, field, offset, target_offset);
@@ -129,15 +135,6 @@ fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         debug!("    padding before: {:?}", padding);
 
         result.push(field.llvm_type(ccx));
-
-        if layout.is_packed() {
-            assert_eq!(padding.bytes(), 0);
-        } else {
-            assert!(field.align.abi() <= layout.align.abi(),
-                    "non-packed type has field with larger align ({}): {:#?}",
-                    field.align.abi(), layout);
-        }
-
         offset = target_offset + field.size;
         prev_align = field.align;
     }
@@ -158,7 +155,7 @@ fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                offset, layout.size);
     }
 
-    result
+    (result, packed)
 }
 
 impl<'a, 'tcx> CrateContext<'a, 'tcx> {
@@ -301,7 +298,8 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
         ccx.lltypes().borrow_mut().insert((self.ty, variant_index), llty);
 
         if let Some((mut llty, layout)) = defer {
-            llty.set_struct_body(&struct_llfields(ccx, layout), layout.is_packed())
+            let (llfields, packed) = struct_llfields(ccx, layout);
+            llty.set_struct_body(&llfields, packed)
         }
 
         llty