about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-04-10 07:37:24 -0700
committerbors <bors@rust-lang.org>2013-04-10 07:37:24 -0700
commit5d01f649b4cda55cb6ec358d0e2685c9901f62a1 (patch)
tree5b3ff73e1777657e481d1f45d625bc996722b624
parenta425b75c6490df3567be3bf2c0437a395d295ed8 (diff)
parent7d7e149748846a306df56fae873db66b47a97a12 (diff)
auto merge of #5816 : dbaupp/rust/rustc-packed-v2, r=nikomatsakis
#5758 take 2.

This adds a `#[packed]` attribute for structs, like GCC's `__attribute__((packed))`, e.g.

```rust
#[packed]
struct Size5 {
   a: u8,
   b: u32
}
```

It works on normal and tuple structs, but is (silently) ignored on enums.

Closes #1704.
-rw-r--r--src/librustc/middle/trans/adt.rs20
-rw-r--r--src/librustc/middle/trans/asm.rs4
-rw-r--r--src/librustc/middle/trans/base.rs8
-rw-r--r--src/librustc/middle/trans/cabi_arm.rs23
-rw-r--r--src/librustc/middle/trans/cabi_mips.rs27
-rw-r--r--src/librustc/middle/trans/cabi_x86_64.rs23
-rw-r--r--src/librustc/middle/trans/common.rs44
-rw-r--r--src/librustc/middle/trans/foreign.rs5
-rw-r--r--src/librustc/middle/trans/machine.rs6
-rw-r--r--src/librustc/middle/trans/type_of.rs36
-rw-r--r--src/librustc/middle/ty.rs25
-rw-r--r--src/test/compile-fail/packed-struct-generic-transmute.rs35
-rw-r--r--src/test/compile-fail/packed-struct-transmute.rs35
-rw-r--r--src/test/run-pass/packed-struct-borrow-element.rs22
-rw-r--r--src/test/run-pass/packed-struct-generic-layout.rs35
-rw-r--r--src/test/run-pass/packed-struct-generic-size.rs25
-rw-r--r--src/test/run-pass/packed-struct-layout.rs34
-rw-r--r--src/test/run-pass/packed-struct-match.rs25
-rw-r--r--src/test/run-pass/packed-struct-size.rs58
-rw-r--r--src/test/run-pass/packed-struct-vec.rs30
-rw-r--r--src/test/run-pass/packed-tuple-struct-layout.rs28
-rw-r--r--src/test/run-pass/packed-tuple-struct-size.rs44
22 files changed, 521 insertions, 71 deletions
diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs
index b854addf0b1..36958fa706e 100644
--- a/src/librustc/middle/trans/adt.rs
+++ b/src/librustc/middle/trans/adt.rs
@@ -88,6 +88,7 @@ pub enum Repr {
 struct Struct {
     size: u64,
     align: u64,
+    packed: bool,
     fields: ~[ty::t]
 }
 
@@ -109,17 +110,18 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
     }
     let repr = @match ty::get(t).sty {
         ty::ty_tup(ref elems) => {
-            Univariant(mk_struct(cx, *elems), false)
+            Univariant(mk_struct(cx, *elems, false), false)
         }
         ty::ty_struct(def_id, ref substs) => {
             let fields = ty::lookup_struct_fields(cx.tcx, def_id);
             let ftys = do fields.map |field| {
                 ty::lookup_field_type(cx.tcx, def_id, field.id, substs)
             };
+            let packed = ty::lookup_packed(cx.tcx, def_id);
             let dtor = ty::ty_dtor(cx.tcx, def_id).is_present();
             let ftys =
                 if dtor { ftys + [ty::mk_bool(cx.tcx)] } else { ftys };
-            Univariant(mk_struct(cx, ftys), dtor)
+            Univariant(mk_struct(cx, ftys, packed), dtor)
         }
         ty::ty_enum(def_id, ref substs) => {
             struct Case { discr: int, tys: ~[ty::t] };
@@ -132,7 +134,7 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
             };
             if cases.len() == 0 {
                 // Uninhabitable; represent as unit
-                Univariant(mk_struct(cx, ~[]), false)
+                Univariant(mk_struct(cx, ~[], false), false)
             } else if cases.all(|c| c.tys.len() == 0) {
                 // All bodies empty -> intlike
                 let discrs = cases.map(|c| c.discr);
@@ -140,7 +142,7 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
             } else if cases.len() == 1 {
                 // Equivalent to a struct/tuple/newtype.
                 assert!(cases[0].discr == 0);
-                Univariant(mk_struct(cx, cases[0].tys), false)
+                Univariant(mk_struct(cx, cases[0].tys, false), false)
             } else {
                 // The general case.  Since there's at least one
                 // non-empty body, explicit discriminants should have
@@ -151,7 +153,7 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
                                      ty::item_path_str(cx.tcx, def_id)))
                 }
                 let discr = ~[ty::mk_int(cx.tcx)];
-                General(cases.map(|c| mk_struct(cx, discr + c.tys)))
+                General(cases.map(|c| mk_struct(cx, discr + c.tys, false)))
             }
         }
         _ => cx.sess.bug(~"adt::represent_type called on non-ADT type")
@@ -160,12 +162,13 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
     return repr;
 }
 
-fn mk_struct(cx: @CrateContext, tys: &[ty::t]) -> Struct {
+fn mk_struct(cx: @CrateContext, tys: &[ty::t], packed: bool) -> Struct {
     let lltys = tys.map(|&ty| type_of::sizing_type_of(cx, ty));
-    let llty_rec = T_struct(lltys);
+    let llty_rec = T_struct(lltys, packed);
     Struct {
         size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64,
         align: machine::llalign_of_min(cx, llty_rec) /*bad*/as u64,
+        packed: packed,
         fields: vec::from_slice(tys)
     }
 }
@@ -358,7 +361,8 @@ fn struct_field_ptr(bcx: block, st: &Struct, val: ValueRef, ix: uint,
 
     let val = if needs_cast {
         let real_llty = T_struct(st.fields.map(
-            |&ty| type_of::type_of(ccx, ty)));
+            |&ty| type_of::type_of(ccx, ty)),
+                                 st.packed);
         PointerCast(bcx, val, T_ptr(real_llty))
     } else {
         val
diff --git a/src/librustc/middle/trans/asm.rs b/src/librustc/middle/trans/asm.rs
index b3b23a8730d..cbcefdd5fdb 100644
--- a/src/librustc/middle/trans/asm.rs
+++ b/src/librustc/middle/trans/asm.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -108,7 +108,7 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block {
     } else if numOutputs == 1 {
         val_ty(outputs[0])
     } else {
-        T_struct(outputs.map(|o| val_ty(*o)))
+        T_struct(outputs.map(|o| val_ty(*o)), false)
     };
 
     let dialect = match ia.dialect {
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 2eb7f8332ca..d94f2bf3c2f 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -938,7 +938,7 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef {
     // The landing pad return type (the type being propagated). Not sure what
     // this represents but it's determined by the personality function and
     // this is what the EH proposal example uses.
-    let llretty = T_struct(~[T_ptr(T_i8()), T_i32()]);
+    let llretty = T_struct(~[T_ptr(T_i8()), T_i32()], false);
     // The exception handling personality function. This is the C++
     // personality function __gxx_personality_v0, wrapped in our naming
     // convention.
@@ -2837,7 +2837,7 @@ pub fn decl_gc_metadata(ccx: @CrateContext, llmod_id: &str) {
 }
 
 pub fn create_module_map(ccx: @CrateContext) -> ValueRef {
-    let elttype = T_struct(~[ccx.int_type, ccx.int_type]);
+    let elttype = T_struct(~[ccx.int_type, ccx.int_type], false);
     let maptype = T_array(elttype, ccx.module_data.len() + 1);
     let map = str::as_c_str(~"_rust_mod_map", |buf| {
         unsafe {
@@ -2877,7 +2877,7 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta,
     };
     let sym_name = ~"_rust_crate_map_" + mapname;
     let arrtype = T_array(int_type, n_subcrates as uint);
-    let maptype = T_struct(~[T_i32(), T_ptr(T_i8()), int_type, arrtype]);
+    let maptype = T_struct(~[T_i32(), T_ptr(T_i8()), int_type, arrtype], false);
     let map = str::as_c_str(sym_name, |buf| {
         unsafe {
             llvm::LLVMAddGlobal(llmod, maptype, buf)
diff --git a/src/librustc/middle/trans/cabi_arm.rs b/src/librustc/middle/trans/cabi_arm.rs
index a16b3672b7a..1b94e990545 100644
--- a/src/librustc/middle/trans/cabi_arm.rs
+++ b/src/librustc/middle/trans/cabi_arm.rs
@@ -12,6 +12,7 @@ use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
 use lib::llvm::struct_tys;
 use lib::llvm::TypeRef;
 use lib::llvm::{Attribute, StructRetAttribute};
+use lib::llvm::True;
 use middle::trans::cabi::{ABIInfo, FnType, LLVMType};
 use middle::trans::common::{T_i8, T_i16, T_i32, T_i64};
 use middle::trans::common::{T_array, T_ptr, T_void};
@@ -39,8 +40,12 @@ fn ty_align(ty: TypeRef) -> uint {
             Float => 4,
             Double => 8,
             Struct => {
-                do vec::foldl(1, struct_tys(ty)) |a, t| {
-                    uint::max(a, ty_align(*t))
+                if llvm::LLVMIsPackedStruct(ty) == True {
+                    1
+                } else {
+                    do vec::foldl(1, struct_tys(ty)) |a, t| {
+                        uint::max(a, ty_align(*t))
+                    }
                 }
             }
             Array => {
@@ -62,10 +67,16 @@ fn ty_size(ty: TypeRef) -> uint {
             Float => 4,
             Double => 8,
             Struct => {
-                let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
-                    align(s, *t) + ty_size(*t)
-                };
-                align(size, ty)
+                if llvm::LLVMIsPackedStruct(ty) == True {
+                    do vec::foldl(0, struct_tys(ty)) |s, t| {
+                        s + ty_size(*t)
+                    }
+                } else {
+                    let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
+                        align(s, *t) + ty_size(*t)
+                    };
+                    align(size, ty)
+                }
             }
             Array => {
                 let len = llvm::LLVMGetArrayLength(ty) as uint;
diff --git a/src/librustc/middle/trans/cabi_mips.rs b/src/librustc/middle/trans/cabi_mips.rs
index 1e05cf258c7..ce37455560b 100644
--- a/src/librustc/middle/trans/cabi_mips.rs
+++ b/src/librustc/middle/trans/cabi_mips.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -14,6 +14,7 @@ use core::libc::c_uint;
 use lib::llvm::{llvm, TypeRef, Integer, Pointer, Float, Double};
 use lib::llvm::{Struct, Array, Attribute};
 use lib::llvm::{StructRetAttribute};
+use lib::llvm::True;
 use middle::trans::common::*;
 use middle::trans::cabi::*;
 
@@ -49,8 +50,12 @@ fn ty_align(ty: TypeRef) -> uint {
             Float => 4,
             Double => 8,
             Struct => {
-              do vec::foldl(1, struct_tys(ty)) |a, t| {
-                  uint::max(a, ty_align(*t))
+              if llvm::LLVMIsPackedStruct(ty) == True {
+                1
+              } else {
+                do vec::foldl(1, struct_tys(ty)) |a, t| {
+                    uint::max(a, ty_align(*t))
+                }
               }
             }
             Array => {
@@ -72,10 +77,16 @@ fn ty_size(ty: TypeRef) -> uint {
             Float => 4,
             Double => 8,
             Struct => {
-              let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
-                  align(s, *t) + ty_size(*t)
-              };
-              align(size, ty)
+                if llvm::LLVMIsPackedStruct(ty) == True {
+                    do vec::foldl(0, struct_tys(ty)) |s, t| {
+                        s + ty_size(*t)
+                    }
+                } else {
+                    let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
+                        align(s, *t) + ty_size(*t)
+                    };
+                    align(size, ty)
+                }
             }
             Array => {
               let len = llvm::LLVMGetArrayLength(ty) as uint;
@@ -174,7 +185,7 @@ fn struct_ty(ty: TypeRef,
         fields.push(ty);
     }
 
-    return T_struct(fields);
+    return T_struct(fields, false);
 }
 
 enum MIPS_ABIInfo { MIPS_ABIInfo }
diff --git a/src/librustc/middle/trans/cabi_x86_64.rs b/src/librustc/middle/trans/cabi_x86_64.rs
index 896ebd16257..0e4bf5ce574 100644
--- a/src/librustc/middle/trans/cabi_x86_64.rs
+++ b/src/librustc/middle/trans/cabi_x86_64.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -15,6 +15,7 @@ use lib::llvm::{llvm, TypeRef, Integer, Pointer, Float, Double};
 use lib::llvm::{Struct, Array, Attribute};
 use lib::llvm::{StructRetAttribute, ByValAttribute};
 use lib::llvm::struct_tys;
+use lib::llvm::True;
 use middle::trans::common::*;
 use middle::trans::cabi::*;
 
@@ -76,8 +77,12 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] {
                 Float => 4,
                 Double => 8,
                 Struct => {
-                  do vec::foldl(1, struct_tys(ty)) |a, t| {
+                  if llvm::LLVMIsPackedStruct(ty) == True {
+                    1
+                  } else {
+                    do vec::foldl(1, struct_tys(ty)) |a, t| {
                       uint::max(a, ty_align(*t))
+                    }
                   }
                 }
                 Array => {
@@ -99,10 +104,16 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] {
                 Float => 4,
                 Double => 8,
                 Struct => {
-                  let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
+                  if llvm::LLVMIsPackedStruct(ty) == True {
+                    do vec::foldl(0, struct_tys(ty)) |s, t| {
+                      s + ty_size(*t)
+                    }
+                  } else {
+                    let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
                       align(s, *t) + ty_size(*t)
-                  };
-                  align(size, ty)
+                    };
+                    align(size, ty)
+                  }
                 }
                 Array => {
                   let len = llvm::LLVMGetArrayLength(ty) as uint;
@@ -308,7 +319,7 @@ fn llreg_ty(cls: &[x86_64_reg_class]) -> TypeRef {
             }
             i += 1u;
         }
-        return T_struct(tys);
+        return T_struct(tys, false);
     }
 }
 
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index 2cfd7a25d68..4701a166ea7 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -765,7 +765,7 @@ pub fn T_void() -> TypeRef {
 }
 
 pub fn T_nil() -> TypeRef {
-    return T_struct(~[])
+    return T_struct(~[], false)
 }
 
 pub fn T_metadata() -> TypeRef { unsafe { return llvm::LLVMMetadataType(); } }
@@ -848,7 +848,7 @@ pub fn T_fn(inputs: &[TypeRef], output: TypeRef) -> TypeRef {
 }
 
 pub fn T_fn_pair(cx: @CrateContext, tfn: TypeRef) -> TypeRef {
-    return T_struct(~[T_ptr(tfn), T_opaque_cbox_ptr(cx)]);
+    return T_struct(~[T_ptr(tfn), T_opaque_cbox_ptr(cx)], false);
 }
 
 pub fn T_ptr(t: TypeRef) -> TypeRef {
@@ -863,11 +863,11 @@ pub fn T_root(t: TypeRef, addrspace: addrspace) -> TypeRef {
     }
 }
 
-pub fn T_struct(elts: &[TypeRef]) -> TypeRef {
+pub fn T_struct(elts: &[TypeRef], packed: bool) -> TypeRef {
     unsafe {
         return llvm::LLVMStructType(to_ptr(elts),
                                     elts.len() as c_uint,
-                                    False);
+                                    packed as Bool);
     }
 }
 
@@ -878,16 +878,16 @@ pub fn T_named_struct(name: &str) -> TypeRef {
     }
 }
 
-pub fn set_struct_body(t: TypeRef, elts: &[TypeRef]) {
+pub fn set_struct_body(t: TypeRef, elts: &[TypeRef], packed: bool) {
     unsafe {
         llvm::LLVMStructSetBody(t,
                                 to_ptr(elts),
                                 elts.len() as c_uint,
-                                False);
+                                packed as Bool);
     }
 }
 
-pub fn T_empty_struct() -> TypeRef { return T_struct(~[]); }
+pub fn T_empty_struct() -> TypeRef { return T_struct(~[], false); }
 
 // A vtable is, in reality, a vtable pointer followed by zero or more pointers
 // to tydescs and other vtables that it closes over. But the types and number
@@ -913,7 +913,7 @@ pub fn T_task(targ_cfg: @session::config) -> TypeRef {
     let elems =
         ~[t_int, t_int, t_int, t_int,
          t_int, t_int, t_int, t_int];
-    set_struct_body(t, elems);
+    set_struct_body(t, elems, false);
     return t;
 }
 
@@ -956,7 +956,7 @@ pub fn T_tydesc(targ_cfg: @session::config) -> TypeRef {
         ~[int_type, int_type,
           glue_fn_ty, glue_fn_ty, glue_fn_ty, glue_fn_ty,
           T_ptr(T_i8()), T_ptr(T_i8())];
-    set_struct_body(tydesc, elems);
+    set_struct_body(tydesc, elems, false);
     return tydesc;
 }
 
@@ -969,8 +969,9 @@ pub fn T_array(t: TypeRef, n: uint) -> TypeRef {
 // Interior vector.
 pub fn T_vec2(targ_cfg: @session::config, t: TypeRef) -> TypeRef {
     return T_struct(~[T_int(targ_cfg), // fill
-                  T_int(targ_cfg), // alloc
-                  T_array(t, 0u)]); // elements
+                      T_int(targ_cfg), // alloc
+                      T_array(t, 0u)], // elements
+                    false);
 }
 
 pub fn T_vec(ccx: @CrateContext, t: TypeRef) -> TypeRef {
@@ -1001,11 +1002,11 @@ pub fn T_box_header_fields(cx: @CrateContext) -> ~[TypeRef] {
 }
 
 pub fn T_box_header(cx: @CrateContext) -> TypeRef {
-    return T_struct(T_box_header_fields(cx));
+    return T_struct(T_box_header_fields(cx), false);
 }
 
 pub fn T_box(cx: @CrateContext, t: TypeRef) -> TypeRef {
-    return T_struct(vec::append(T_box_header_fields(cx), ~[t]));
+    return T_struct(vec::append(T_box_header_fields(cx), ~[t]), false);
 }
 
 pub fn T_box_ptr(t: TypeRef) -> TypeRef {
@@ -1023,7 +1024,7 @@ pub fn T_opaque_box_ptr(cx: @CrateContext) -> TypeRef {
 }
 
 pub fn T_unique(cx: @CrateContext, t: TypeRef) -> TypeRef {
-    return T_struct(vec::append(T_box_header_fields(cx), ~[t]));
+    return T_struct(vec::append(T_box_header_fields(cx), ~[t]), false);
 }
 
 pub fn T_unique_ptr(t: TypeRef) -> TypeRef {
@@ -1033,12 +1034,12 @@ pub fn T_unique_ptr(t: TypeRef) -> TypeRef {
 }
 
 pub fn T_port(cx: @CrateContext, _t: TypeRef) -> TypeRef {
-    return T_struct(~[cx.int_type]); // Refcount
+    return T_struct(~[cx.int_type], false); // Refcount
 
 }
 
 pub fn T_chan(cx: @CrateContext, _t: TypeRef) -> TypeRef {
-    return T_struct(~[cx.int_type]); // Refcount
+    return T_struct(~[cx.int_type], false); // Refcount
 
 }
 
@@ -1056,21 +1057,22 @@ pub fn T_enum_discrim(cx: @CrateContext) -> TypeRef {
 }
 
 pub fn T_captured_tydescs(cx: @CrateContext, n: uint) -> TypeRef {
-    return T_struct(vec::from_elem::<TypeRef>(n, T_ptr(cx.tydesc_type)));
+    return T_struct(vec::from_elem::<TypeRef>(n, T_ptr(cx.tydesc_type)), false);
 }
 
 pub fn T_opaque_trait(cx: @CrateContext, store: ty::TraitStore) -> TypeRef {
     match store {
         ty::BoxTraitStore => {
-            T_struct(~[T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)])
+            T_struct(~[T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)], false)
         }
         ty::UniqTraitStore => {
             T_struct(~[T_ptr(cx.tydesc_type),
                        T_unique_ptr(T_unique(cx, T_i8())),
-                       T_ptr(cx.tydesc_type)])
+                       T_ptr(cx.tydesc_type)],
+                     false)
         }
         ty::RegionTraitStore(_) => {
-            T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())])
+            T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())], false)
         }
     }
 }
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 7dc2e385e2c..387caa4d8d3 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -106,7 +106,8 @@ fn shim_types(ccx: @CrateContext, id: ast::node_id) -> ShimTypes {
     };
     let llsig = foreign_signature(ccx, &fn_sig);
     let bundle_ty = T_struct(vec::append_one(copy llsig.llarg_tys,
-                                             T_ptr(llsig.llret_ty)));
+                                             T_ptr(llsig.llret_ty)),
+                             false);
     let ret_def =
         !ty::type_is_bot(fn_sig.output) &&
         !ty::type_is_nil(fn_sig.output);
diff --git a/src/librustc/middle/trans/machine.rs b/src/librustc/middle/trans/machine.rs
index 1b9f7bae0e9..cd90f964e45 100644
--- a/src/librustc/middle/trans/machine.rs
+++ b/src/librustc/middle/trans/machine.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -142,9 +142,9 @@ pub fn static_size_of_enum(cx: @CrateContext, t: ty::t) -> uint {
 
                 debug!("static_size_of_enum: variant %s type %s",
                        *cx.tcx.sess.str_of(variant.name),
-                       ty_str(cx.tn, T_struct(lltypes)));
+                       ty_str(cx.tn, T_struct(lltypes, false)));
 
-                let this_size = llsize_of_real(cx, T_struct(lltypes));
+                let this_size = llsize_of_real(cx, T_struct(lltypes, false));
                 if max_size < this_size {
                     max_size = this_size;
                 }
diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs
index a9381647b33..1c94fe28422 100644
--- a/src/librustc/middle/trans/type_of.rs
+++ b/src/librustc/middle/trans/type_of.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -128,11 +128,11 @@ pub fn sizing_type_of(cx: @CrateContext, t: ty::t) -> TypeRef {
 
         ty::ty_estr(ty::vstore_slice(*)) |
         ty::ty_evec(_, ty::vstore_slice(*)) => {
-            T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())])
+            T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())], false)
         }
 
         ty::ty_bare_fn(*) => T_ptr(T_i8()),
-        ty::ty_closure(*) => T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())]),
+        ty::ty_closure(*) => T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())], false),
         ty::ty_trait(_, _, store) => T_opaque_trait(cx, store),
 
         ty::ty_estr(ty::vstore_fixed(size)) => T_array(T_i8(), size),
@@ -142,9 +142,15 @@ pub fn sizing_type_of(cx: @CrateContext, t: ty::t) -> TypeRef {
 
         ty::ty_unboxed_vec(mt) => T_vec(cx, sizing_type_of(cx, mt.ty)),
 
-        ty::ty_tup(*) | ty::ty_struct(*) | ty::ty_enum(*) => {
+        ty::ty_tup(*) | ty::ty_enum(*) => {
             let repr = adt::represent_type(cx, t);
-            T_struct(adt::sizing_fields_of(cx, repr))
+            T_struct(adt::sizing_fields_of(cx, repr), false)
+        }
+
+        ty::ty_struct(did, _) => {
+            let repr = adt::represent_type(cx, t);
+            let packed = ty::lookup_packed(cx.tcx, did);
+            T_struct(adt::sizing_fields_of(cx, repr), packed)
         }
 
         ty::ty_self(_) | ty::ty_infer(*) | ty::ty_param(*) | ty::ty_err(*) => {
@@ -223,12 +229,14 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef {
 
       ty::ty_evec(ref mt, ty::vstore_slice(_)) => {
         T_struct(~[T_ptr(type_of(cx, mt.ty)),
-                   T_uint_ty(cx, ast::ty_u)])
+                   T_uint_ty(cx, ast::ty_u)],
+                 false)
       }
 
       ty::ty_estr(ty::vstore_slice(_)) => {
         T_struct(~[T_ptr(T_i8()),
-                   T_uint_ty(cx, ast::ty_u)])
+                   T_uint_ty(cx, ast::ty_u)],
+                 false)
       }
 
       ty::ty_estr(ty::vstore_fixed(n)) => {
@@ -245,7 +253,7 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef {
       ty::ty_type => T_ptr(cx.tydesc_type),
       ty::ty_tup(*) => {
           let repr = adt::represent_type(cx, t);
-          T_struct(adt::fields_of(cx, repr))
+          T_struct(adt::fields_of(cx, repr), false)
       }
       ty::ty_opaque_closure_ptr(_) => T_opaque_box_ptr(cx),
       ty::ty_struct(did, ref substs) => {
@@ -268,9 +276,17 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef {
 
     // If this was an enum or struct, fill in the type now.
     match ty::get(t).sty {
-      ty::ty_enum(*) | ty::ty_struct(*) => {
+      ty::ty_enum(*) => {
           let repr = adt::represent_type(cx, t);
-          common::set_struct_body(llty, adt::fields_of(cx, repr));
+          common::set_struct_body(llty, adt::fields_of(cx, repr),
+                                  false);
+      }
+
+      ty::ty_struct(did, _) => {
+        let repr = adt::represent_type(cx, t);
+        let packed = ty::lookup_packed(cx.tcx, did);
+        common::set_struct_body(llty, adt::fields_of(cx, repr),
+                                packed);
       }
       _ => ()
     }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 74215312434..335c9824354 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -44,6 +44,7 @@ use std::smallintmap::SmallIntMap;
 use syntax::ast::*;
 use syntax::ast_util::{is_local, local_def};
 use syntax::ast_util;
+use syntax::attr;
 use syntax::codemap::span;
 use syntax::codemap;
 use syntax::print::pprust;
@@ -3933,6 +3934,28 @@ pub fn lookup_trait_def(cx: ctxt, did: ast::def_id) -> @ty::TraitDef {
     }
 }
 
+// Determine whether an item is annotated with #[packed] or not
+pub fn lookup_packed(tcx: ctxt,
+                  did: def_id) -> bool {
+    if is_local(did) {
+        match tcx.items.find(&did.node) {
+            Some(
+                &ast_map::node_item(@ast::item {
+                    attrs: ref attrs,
+                    _
+                }, _)) => attr::attrs_contains_name(*attrs, "packed"),
+            _ => tcx.sess.bug(fmt!("lookup_packed: %? is not an item",
+                                   did))
+        }
+    } else {
+        let mut ret = false;
+        do csearch::get_item_attrs(tcx.cstore, did) |meta_items| {
+            ret = attr::contains_name(meta_items, "packed");
+        }
+        ret
+    }
+}
+
 // Look up a field ID, whether or not it's local
 // Takes a list of type substs in case the struct is generic
 pub fn lookup_field_type(tcx: ctxt,
diff --git a/src/test/compile-fail/packed-struct-generic-transmute.rs b/src/test/compile-fail/packed-struct-generic-transmute.rs
new file mode 100644
index 00000000000..3ed9d00be28
--- /dev/null
+++ b/src/test/compile-fail/packed-struct-generic-transmute.rs
@@ -0,0 +1,35 @@
+// Copyright 2013 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.
+
+// This assumes the packed and non-packed structs are different sizes.
+
+// the error points to the start of the file, not the line with the
+// transmute
+
+// error-pattern: reinterpret_cast called on types with different size
+
+#[packed]
+struct Foo<T,S> {
+    bar: T,
+    baz: S
+}
+
+struct Oof<T, S> {
+    rab: T,
+    zab: S
+}
+
+fn main() {
+    let foo = Foo { bar: [1u8, 2, 3, 4, 5], baz: 10i32 };
+    unsafe {
+        let oof: Oof<[u8, .. 5], i32> = cast::transmute(foo);
+        debug!(oof);
+    }
+}
diff --git a/src/test/compile-fail/packed-struct-transmute.rs b/src/test/compile-fail/packed-struct-transmute.rs
new file mode 100644
index 00000000000..d2aca3c0d6b
--- /dev/null
+++ b/src/test/compile-fail/packed-struct-transmute.rs
@@ -0,0 +1,35 @@
+// Copyright 2013 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.
+
+// This assumes the packed and non-packed structs are different sizes.
+
+// the error points to the start of the file, not the line with the
+// transmute
+
+// error-pattern: reinterpret_cast called on types with different size
+
+#[packed]
+struct Foo {
+    bar: u8,
+    baz: uint
+}
+
+struct Oof {
+    rab: u8,
+    zab: uint
+}
+
+fn main() {
+    let foo = Foo { bar: 1, baz: 10 };
+    unsafe {
+        let oof: Oof = cast::transmute(foo);
+        debug!(oof);
+    }
+}
diff --git a/src/test/run-pass/packed-struct-borrow-element.rs b/src/test/run-pass/packed-struct-borrow-element.rs
new file mode 100644
index 00000000000..a331b80a894
--- /dev/null
+++ b/src/test/run-pass/packed-struct-borrow-element.rs
@@ -0,0 +1,22 @@
+// Copyright 2013 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.
+
+#[packed]
+struct Foo {
+    bar: u8,
+    baz: uint
+}
+
+fn main() {
+    let foo = Foo { bar: 1, baz: 2 };
+    let brw = &foo.baz;
+
+    assert_eq!(*brw, 2);
+}
diff --git a/src/test/run-pass/packed-struct-generic-layout.rs b/src/test/run-pass/packed-struct-generic-layout.rs
new file mode 100644
index 00000000000..fd6e3b670f5
--- /dev/null
+++ b/src/test/run-pass/packed-struct-generic-layout.rs
@@ -0,0 +1,35 @@
+// Copyright 2013 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.
+
+#[packed]
+struct S<T, S> {
+    a: T,
+    b: u8,
+    c: S
+}
+
+fn main() {
+    unsafe {
+        let s = S { a: 0xff_ff_ff_ffu32, b: 1, c: 0xaa_aa_aa_aa as i32 };
+        let transd : [u8, .. 9] = cast::transmute(s);
+        // Don't worry about endianness, the numbers are palindromic.
+        assert_eq!(transd,
+                   [0xff, 0xff, 0xff, 0xff,
+                    1,
+                    0xaa, 0xaa, 0xaa, 0xaa]);
+
+
+        let s = S { a: 1u8, b: 2u8, c: 0b10000001_10000001 as i16};
+        let transd : [u8, .. 4] = cast::transmute(s);
+        // Again, no endianness problems.
+        assert_eq!(transd,
+                   [1, 2, 0b10000001, 0b10000001]);
+    }
+}
diff --git a/src/test/run-pass/packed-struct-generic-size.rs b/src/test/run-pass/packed-struct-generic-size.rs
new file mode 100644
index 00000000000..a5c4d5385a2
--- /dev/null
+++ b/src/test/run-pass/packed-struct-generic-size.rs
@@ -0,0 +1,25 @@
+// Copyright 2013 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.
+
+#[packed]
+struct S<T, S> {
+    a: T,
+    b: u8,
+    c: S
+}
+
+fn main() {
+    assert_eq!(sys::size_of::<S<u8, u8>>(), 3);
+
+    assert_eq!(sys::size_of::<S<u64, u16>>(), 11);
+
+    assert_eq!(sys::size_of::<S<~str, @mut [int]>>(),
+               1 + sys::size_of::<~str>() + sys::size_of::<@mut [int]>());
+}
diff --git a/src/test/run-pass/packed-struct-layout.rs b/src/test/run-pass/packed-struct-layout.rs
new file mode 100644
index 00000000000..8d27e55e191
--- /dev/null
+++ b/src/test/run-pass/packed-struct-layout.rs
@@ -0,0 +1,34 @@
+// Copyright 2013 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.
+
+#[packed]
+struct S4 {
+    a: u8,
+    b: [u8, .. 3],
+}
+
+#[packed]
+struct S5 {
+    a: u8,
+    b: u32
+}
+
+fn main() {
+    unsafe {
+        let s4 = S4 { a: 1, b: [2,3,4] };
+        let transd : [u8, .. 4] = cast::transmute(s4);
+        assert_eq!(transd, [1, 2, 3, 4]);
+
+        let s5 = S5 { a: 1, b: 0xff_00_00_ff };
+        let transd : [u8, .. 5] = cast::transmute(s5);
+        // Don't worry about endianness, the u32 is palindromic.
+        assert_eq!(transd, [1, 0xff, 0, 0, 0xff]);
+    }
+}
diff --git a/src/test/run-pass/packed-struct-match.rs b/src/test/run-pass/packed-struct-match.rs
new file mode 100644
index 00000000000..15e7b6b0ce0
--- /dev/null
+++ b/src/test/run-pass/packed-struct-match.rs
@@ -0,0 +1,25 @@
+// Copyright 2013 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.
+
+#[packed]
+struct Foo {
+    bar: u8,
+    baz: uint
+}
+
+fn main() {
+    let foo = Foo { bar: 1, baz: 2 };
+    match foo {
+        Foo {bar, baz} => {
+            assert_eq!(bar, 1);
+            assert_eq!(baz, 2);
+        }
+    }
+}
diff --git a/src/test/run-pass/packed-struct-size.rs b/src/test/run-pass/packed-struct-size.rs
new file mode 100644
index 00000000000..372fe3d37f6
--- /dev/null
+++ b/src/test/run-pass/packed-struct-size.rs
@@ -0,0 +1,58 @@
+// Copyright 2013 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.
+
+#[packed]
+struct S4 {
+    a: u8,
+    b: [u8, .. 3],
+}
+
+#[packed]
+struct S5 {
+    a: u8,
+    b: u32
+}
+
+#[packed]
+struct S13_str {
+    a: i64,
+    b: f32,
+    c: u8,
+    d: ~str
+}
+
+enum Foo {
+    Bar = 1,
+    Baz = 2
+}
+
+#[packed]
+struct S3_Foo {
+    a: u8,
+    b: u16,
+    c: Foo
+}
+
+#[packed]
+struct S7_Option {
+    a: f32,
+    b: u8,
+    c: u16,
+    d: Option<@mut f64>
+}
+
+
+fn main() {
+    assert_eq!(sys::size_of::<S4>(), 4);
+    assert_eq!(sys::size_of::<S5>(), 5);
+    assert_eq!(sys::size_of::<S13_str>(), 13 + sys::size_of::<~str>());
+    assert_eq!(sys::size_of::<S3_Foo>(), 3 + sys::size_of::<Foo>());
+    assert_eq!(sys::size_of::<S7_Option>(), 7 + sys::size_of::<Option<@mut f64>>());
+}
diff --git a/src/test/run-pass/packed-struct-vec.rs b/src/test/run-pass/packed-struct-vec.rs
new file mode 100644
index 00000000000..b1ac29b7721
--- /dev/null
+++ b/src/test/run-pass/packed-struct-vec.rs
@@ -0,0 +1,30 @@
+// Copyright 2013 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.
+
+#[packed]
+#[deriving(Eq)]
+struct Foo {
+    bar: u8,
+    baz: u64
+}
+
+fn main() {
+    let foos = [Foo { bar: 1, baz: 2 }, .. 10];
+
+    assert_eq!(sys::size_of::<[Foo, .. 10]>(), 90);
+
+    for uint::range(0, 10) |i| {
+        assert_eq!(foos[i], Foo { bar: 1, baz: 2});
+    }
+
+    for foos.each |&foo| {
+        assert_eq!(foo, Foo { bar: 1, baz: 2 });
+    }
+}
diff --git a/src/test/run-pass/packed-tuple-struct-layout.rs b/src/test/run-pass/packed-tuple-struct-layout.rs
new file mode 100644
index 00000000000..9c2fe621a32
--- /dev/null
+++ b/src/test/run-pass/packed-tuple-struct-layout.rs
@@ -0,0 +1,28 @@
+// Copyright 2013 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.
+
+#[packed]
+struct S4(u8,[u8, .. 3]);
+
+#[packed]
+struct S5(u8,u32);
+
+fn main() {
+    unsafe {
+        let s4 = S4(1, [2,3,4]);
+        let transd : [u8, .. 4] = cast::transmute(s4);
+        assert_eq!(transd, [1, 2, 3, 4]);
+
+        let s5 = S5(1, 0xff_00_00_ff);
+        let transd : [u8, .. 5] = cast::transmute(s5);
+        // Don't worry about endianness, the u32 is palindromic.
+        assert_eq!(transd, [1, 0xff, 0, 0, 0xff]);
+    }
+}
diff --git a/src/test/run-pass/packed-tuple-struct-size.rs b/src/test/run-pass/packed-tuple-struct-size.rs
new file mode 100644
index 00000000000..23faa2eb0ad
--- /dev/null
+++ b/src/test/run-pass/packed-tuple-struct-size.rs
@@ -0,0 +1,44 @@
+// Copyright 2013 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.
+
+#[packed]
+struct S4(u8,[u8, .. 3]);
+
+#[packed]
+struct S5(u8, u32);
+
+#[packed]
+struct S13_str(i64, f32, u8, ~str);
+
+enum Foo {
+    Bar = 1,
+    Baz = 2
+}
+
+#[packed]
+struct S3_Foo(u8, u16, Foo);
+
+#[packed]
+struct S7_Option(f32, u8, u16, Option<@mut f64>);
+
+fn main() {
+    assert_eq!(sys::size_of::<S4>(), 4);
+
+    assert_eq!(sys::size_of::<S5>(), 5);
+
+    assert_eq!(sys::size_of::<S13_str>(),
+               13 + sys::size_of::<~str>());
+
+    assert_eq!(sys::size_of::<S3_Foo>(),
+               3 + sys::size_of::<Foo>());
+
+    assert_eq!(sys::size_of::<S7_Option>(),
+              7 + sys::size_of::<Option<@mut f64>>());
+}