about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-08-26 19:23:42 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-09-03 13:39:35 +0300
commit93067ca089ea570e4e2bdfc456958c81a4d1e092 (patch)
treedcc0960db713f309dc92dd2fa23bfb596b9b9e8a /src
parente67c2282afa3c527da49618b928280564e92868f (diff)
downloadrust-93067ca089ea570e4e2bdfc456958c81a4d1e092.tar.gz
rust-93067ca089ea570e4e2bdfc456958c81a4d1e092.zip
Address comments and add requested tests
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/expr_use_visitor.rs43
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/restrictions.rs1
-rw-r--r--src/librustc_borrowck/borrowck/move_data.rs12
-rw-r--r--src/librustc_privacy/lib.rs23
-rw-r--r--src/librustc_trans/glue.rs8
-rw-r--r--src/librustc_typeck/check/_match.rs9
-rw-r--r--src/rt/rust_test_helpers.c21
-rw-r--r--src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs (renamed from src/test/compile-fail/union-borrow-nested.rs)0
-rw-r--r--src/test/compile-fail/borrowck/borrowck-union-borrow.rs (renamed from src/test/compile-fail/union-borrow.rs)0
-rw-r--r--src/test/compile-fail/borrowck/borrowck-union-move-assign.rs (renamed from src/test/compile-fail/union-move-assign.rs)0
-rw-r--r--src/test/compile-fail/borrowck/borrowck-union-move.rs (renamed from src/test/compile-fail/union-move.rs)0
-rw-r--r--src/test/compile-fail/borrowck/borrowck-union-uninitialized.rs (renamed from src/test/compile-fail/union-uninitialized.rs)0
-rw-r--r--src/test/compile-fail/privacy/union-field-privacy-1.rs30
-rw-r--r--src/test/compile-fail/privacy/union-field-privacy-2.rs28
-rw-r--r--src/test/compile-fail/union/union-const-eval.rs (renamed from src/test/compile-fail/union-const-eval.rs)0
-rw-r--r--src/test/compile-fail/union/union-const-pat.rs (renamed from src/test/compile-fail/union-const-pat.rs)0
-rw-r--r--src/test/compile-fail/union/union-copy.rs26
-rw-r--r--src/test/compile-fail/union/union-derive.rs (renamed from src/test/compile-fail/union-derive.rs)0
-rw-r--r--src/test/compile-fail/union/union-empty.rs (renamed from src/test/compile-fail/union-empty.rs)0
-rw-r--r--src/test/compile-fail/union/union-feature-gate.rs15
-rw-r--r--src/test/compile-fail/union/union-fields.rs (renamed from src/test/compile-fail/union-fields.rs)11
-rw-r--r--src/test/compile-fail/union/union-generic.rs24
-rw-r--r--src/test/compile-fail/union/union-nonrepresentable.rs (renamed from src/test/compile-fail/union-nonrepresentable.rs)0
-rw-r--r--src/test/compile-fail/union/union-repr-c.rs29
-rw-r--r--src/test/compile-fail/union/union-suggest-field.rs29
-rw-r--r--src/test/compile-fail/union/union-unsafe.rs (renamed from src/test/compile-fail/union-unsafe.rs)7
-rw-r--r--src/test/compile-fail/union/union-unsized.rs (renamed from src/test/compile-fail/union-unsized.rs)6
-rw-r--r--src/test/compile-fail/union/union-with-drop-fields-lint.rs (renamed from src/test/compile-fail/union-with-drop-fields-lint.rs)0
-rw-r--r--src/test/run-pass/union/auxiliary/union.rs (renamed from src/test/run-pass/auxiliary/union.rs)0
-rw-r--r--src/test/run-pass/union/union-backcomp.rs (renamed from src/test/run-pass/union-backcomp.rs)4
-rw-r--r--src/test/run-pass/union/union-basic.rs (renamed from src/test/run-pass/union-basic.rs)0
-rw-r--r--src/test/run-pass/union/union-c-interop.rs47
-rw-r--r--src/test/run-pass/union/union-const-trans.rs (renamed from src/test/run-pass/union-const-trans.rs)0
-rw-r--r--src/test/run-pass/union/union-derive.rs (renamed from src/test/run-pass/union-derive.rs)0
-rw-r--r--src/test/run-pass/union/union-drop-assign.rs (renamed from src/test/run-pass/union-drop-assign.rs)0
-rw-r--r--src/test/run-pass/union/union-drop.rs (renamed from src/test/run-pass/union-drop.rs)0
-rw-r--r--src/test/run-pass/union/union-generic.rs43
-rw-r--r--src/test/run-pass/union/union-inherent-method.rs (renamed from src/test/compile-fail/union-field-privacy.rs)13
-rw-r--r--src/test/run-pass/union/union-macro.rs33
-rw-r--r--src/test/run-pass/union/union-overwrite.rs80
-rw-r--r--src/test/run-pass/union/union-packed.rs (renamed from src/test/run-pass/union-packed.rs)30
-rw-r--r--src/test/run-pass/union/union-pat-refutability.rs (renamed from src/test/run-pass/union-pat-refutability.rs)0
-rw-r--r--src/test/run-pass/union/union-trait-impl.rs27
-rw-r--r--src/test/run-pass/union/union-transmute.rs (renamed from src/test/run-pass/union-transmute.rs)0
-rw-r--r--src/test/run-pass/union/union-with-drop-fields-lint.rs42
-rw-r--r--src/test/run-pass/union/union-xcrate.rs (renamed from src/test/run-pass/union-xcrate.rs)0
47 files changed, 582 insertions, 61 deletions
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index a6835802f1c..541aeeb7d8d 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -671,31 +671,28 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
         // Select just those fields of the `with`
         // expression that will actually be used
-        match with_cmt.ty.sty {
-            ty::TyStruct(def, substs) => {
-                // Consume those fields of the with expression that are needed.
-                for with_field in &def.struct_variant().fields {
-                    if !contains_field_named(with_field, fields) {
-                        let cmt_field = self.mc.cat_field(
-                            &*with_expr,
-                            with_cmt.clone(),
-                            with_field.name,
-                            with_field.ty(self.tcx(), substs)
-                        );
-                        self.delegate_consume(with_expr.id, with_expr.span, cmt_field);
-                    }
+        if let ty::TyStruct(def, substs) = with_cmt.ty.sty {
+            // Consume those fields of the with expression that are needed.
+            for with_field in &def.struct_variant().fields {
+                if !contains_field_named(with_field, fields) {
+                    let cmt_field = self.mc.cat_field(
+                        &*with_expr,
+                        with_cmt.clone(),
+                        with_field.name,
+                        with_field.ty(self.tcx(), substs)
+                    );
+                    self.delegate_consume(with_expr.id, with_expr.span, cmt_field);
                 }
             }
-            _ => {
-                // the base expression should always evaluate to a
-                // struct; however, when EUV is run during typeck, it
-                // may not. This will generate an error earlier in typeck,
-                // so we can just ignore it.
-                if !self.tcx().sess.has_errors() {
-                    span_bug!(
-                        with_expr.span,
-                        "with expression doesn't evaluate to a struct");
-                }
+        } else {
+            // the base expression should always evaluate to a
+            // struct; however, when EUV is run during typeck, it
+            // may not. This will generate an error earlier in typeck,
+            // so we can just ignore it.
+            if !self.tcx().sess.has_errors() {
+                span_bug!(
+                    with_expr.span,
+                    "with expression doesn't evaluate to a struct");
             }
         }
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index ee2188e8e11..e88f72f2d84 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1423,7 +1423,7 @@ bitflags! {
         const IS_PHANTOM_DATA     = 1 << 3,
         const IS_SIMD             = 1 << 4,
         const IS_FUNDAMENTAL      = 1 << 5,
-        const IS_UNION            = 1 << 7,
+        const IS_UNION            = 1 << 6,
     }
 }
 
diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
index 6193157fa7b..c08dc9330b8 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
@@ -102,6 +102,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
                 let interior = interior.cleaned();
                 let base_ty = cmt_base.ty;
                 let result = self.restrict(cmt_base);
+                // Borrowing one union field automatically borrows all its fields.
                 if let ty::TyUnion(ref adt_def, _) = base_ty.sty {
                     match result {
                         RestrictionResult::Safe => RestrictionResult::Safe,
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index b13291b8419..236a1a2835c 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -442,12 +442,12 @@ impl<'a, 'tcx> MoveData<'tcx> {
         self.add_assignment_helper(tcx, lp.clone(), assign_id, span, assignee_id, mode);
     }
 
-    pub fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 lp: Rc<LoanPath<'tcx>>,
-                                 assign_id: ast::NodeId,
-                                 span: Span,
-                                 assignee_id: ast::NodeId,
-                                 mode: euv::MutateMode) {
+    fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                             lp: Rc<LoanPath<'tcx>>,
+                             assign_id: ast::NodeId,
+                             span: Span,
+                             assignee_id: ast::NodeId,
+                             mode: euv::MutateMode) {
         debug!("add_assignment(lp={:?}, assign_id={}, assignee_id={}",
                lp, assign_id, assignee_id);
 
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 6b291c69307..179863c16ff 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -429,19 +429,24 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
                 let method = self.tcx.tables.borrow().method_map[&method_call];
                 self.check_method(expr.span, method.def_id);
             }
-            hir::ExprStruct(_, ref fields, _) => {
+            hir::ExprStruct(_, ref expr_fields, _) => {
                 let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap();
                 let variant = adt.variant_of_def(self.tcx.expect_def(expr.id));
                 // RFC 736: ensure all unmentioned fields are visible.
                 // Rather than computing the set of unmentioned fields
-                // (i.e. `all_fields - fields`), just check them all.
-                for field in variant.fields.iter() {
-                    let span = if let Some(f) = fields.iter().find(|f| f.name.node == field.name) {
-                        f.span
-                    } else {
-                        expr.span
-                    };
-                    self.check_field(span, adt, field);
+                // (i.e. `all_fields - fields`), just check them all,
+                // unless the ADT is a union, then unmentioned fields
+                // are not checked.
+                if adt.adt_kind() == ty::AdtKind::Union {
+                    for expr_field in expr_fields {
+                        self.check_field(expr.span, adt, variant.field_named(expr_field.name.node));
+                    }
+                } else {
+                    for field in &variant.fields {
+                        let expr_field = expr_fields.iter().find(|f| f.name.node == field.name);
+                        let span = if let Some(f) = expr_field { f.span } else { expr.span };
+                        self.check_field(span, adt, field);
+                    }
                 }
             }
             hir::ExprPath(..) => {
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index bb77db8fd69..34c92f334d0 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -265,13 +265,13 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     fcx.finish(bcx, DebugLoc::None);
 }
 
-fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+fn trans_custom_dtor<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                  t: Ty<'tcx>,
                                  v0: ValueRef,
                                  shallow_drop: bool)
                                  -> Block<'blk, 'tcx>
 {
-    debug!("trans_struct_drop t: {}", t);
+    debug!("trans_custom_dtor t: {}", t);
     let tcx = bcx.tcx();
     let mut bcx = bcx;
 
@@ -489,11 +489,11 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
         }
         ty::TyStruct(def, _) | ty::TyEnum(def, _)
                 if def.dtor_kind().is_present() && !skip_dtor => {
-            trans_struct_drop(bcx, t, v0, false)
+            trans_custom_dtor(bcx, t, v0, false)
         }
         ty::TyUnion(def, _) => {
             if def.dtor_kind().is_present() && !skip_dtor {
-                trans_struct_drop(bcx, t, v0, true)
+                trans_custom_dtor(bcx, t, v0, true)
             } else {
                 bcx
             }
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 5c19fa2a66c..12fce4b928e 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -718,12 +718,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Report an error if incorrect number of the fields were specified.
         if kind_name == "union" {
-            if fields.len() > 1 {
-                tcx.sess.span_err(span, "union patterns can have at most one field");
+            if fields.len() != 1 {
+                tcx.sess.span_err(span, "union patterns should have exactly one field");
             }
-            if fields.is_empty() && !etc {
-                tcx.sess.span_err(span, "union patterns without `..` \
-                                         should have at least one field");
+            if etc {
+                tcx.sess.span_err(span, "`..` cannot be used in union patterns");
             }
         } else if !etc {
             for field in variant.fields
diff --git a/src/rt/rust_test_helpers.c b/src/rt/rust_test_helpers.c
index d2ebdcca80c..7a04d377608 100644
--- a/src/rt/rust_test_helpers.c
+++ b/src/rt/rust_test_helpers.c
@@ -247,3 +247,24 @@ double rust_interesting_average(uint64_t n, ...) {
 int32_t rust_int8_to_int32(int8_t x) {
     return (int32_t)x;
 }
+
+typedef union LARGE_INTEGER {
+  struct {
+    uint32_t LowPart;
+    uint32_t HighPart;
+  };
+  struct {
+    uint32_t LowPart;
+    uint32_t HighPart;
+  } u;
+  uint64_t QuadPart;
+} LARGE_INTEGER;
+
+LARGE_INTEGER increment_all_parts(LARGE_INTEGER li) {
+    li.LowPart += 1;
+    li.HighPart += 1;
+    li.u.LowPart += 1;
+    li.u.HighPart += 1;
+    li.QuadPart += 1;
+    return li;
+}
diff --git a/src/test/compile-fail/union-borrow-nested.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs
index 19975d79b60..19975d79b60 100644
--- a/src/test/compile-fail/union-borrow-nested.rs
+++ b/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs
diff --git a/src/test/compile-fail/union-borrow.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs
index e8989a3c2d4..e8989a3c2d4 100644
--- a/src/test/compile-fail/union-borrow.rs
+++ b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs
diff --git a/src/test/compile-fail/union-move-assign.rs b/src/test/compile-fail/borrowck/borrowck-union-move-assign.rs
index d4d7bc6b0f7..d4d7bc6b0f7 100644
--- a/src/test/compile-fail/union-move-assign.rs
+++ b/src/test/compile-fail/borrowck/borrowck-union-move-assign.rs
diff --git a/src/test/compile-fail/union-move.rs b/src/test/compile-fail/borrowck/borrowck-union-move.rs
index 5320244cf43..5320244cf43 100644
--- a/src/test/compile-fail/union-move.rs
+++ b/src/test/compile-fail/borrowck/borrowck-union-move.rs
diff --git a/src/test/compile-fail/union-uninitialized.rs b/src/test/compile-fail/borrowck/borrowck-union-uninitialized.rs
index 36e062f8464..36e062f8464 100644
--- a/src/test/compile-fail/union-uninitialized.rs
+++ b/src/test/compile-fail/borrowck/borrowck-union-uninitialized.rs
diff --git a/src/test/compile-fail/privacy/union-field-privacy-1.rs b/src/test/compile-fail/privacy/union-field-privacy-1.rs
new file mode 100644
index 00000000000..4924fabafb0
--- /dev/null
+++ b/src/test/compile-fail/privacy/union-field-privacy-1.rs
@@ -0,0 +1,30 @@
+// Copyright 2016 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.
+
+#![feature(pub_restricted)]
+#![feature(untagged_unions)]
+
+mod m {
+    pub union U {
+        pub a: u8,
+        pub(super) b: u8,
+        c: u8,
+    }
+}
+
+fn main() {
+    let u = m::U { a: 0 }; // OK
+    let u = m::U { b: 0 }; // OK
+    let u = m::U { c: 0 }; //~ ERROR field `c` of union `m::U` is private
+
+    let m::U { a } = u; // OK
+    let m::U { b } = u; // OK
+    let m::U { c } = u; //~ ERROR field `c` of union `m::U` is private
+}
diff --git a/src/test/compile-fail/privacy/union-field-privacy-2.rs b/src/test/compile-fail/privacy/union-field-privacy-2.rs
new file mode 100644
index 00000000000..7151538f412
--- /dev/null
+++ b/src/test/compile-fail/privacy/union-field-privacy-2.rs
@@ -0,0 +1,28 @@
+// Copyright 2016 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.
+
+#![feature(pub_restricted)]
+#![feature(untagged_unions)]
+
+mod m {
+    pub union U {
+        pub a: u8,
+        pub(super) b: u8,
+        c: u8,
+    }
+}
+
+fn main() {
+    let u = m::U { a: 10 };
+
+    let a = u.a; // OK
+    let b = u.b; // OK
+    let c = u.c; //~ ERROR field `c` of struct `m::U` is private
+}
diff --git a/src/test/compile-fail/union-const-eval.rs b/src/test/compile-fail/union/union-const-eval.rs
index b2bf173c59c..b2bf173c59c 100644
--- a/src/test/compile-fail/union-const-eval.rs
+++ b/src/test/compile-fail/union/union-const-eval.rs
diff --git a/src/test/compile-fail/union-const-pat.rs b/src/test/compile-fail/union/union-const-pat.rs
index 3d168980ed2..3d168980ed2 100644
--- a/src/test/compile-fail/union-const-pat.rs
+++ b/src/test/compile-fail/union/union-const-pat.rs
diff --git a/src/test/compile-fail/union/union-copy.rs b/src/test/compile-fail/union/union-copy.rs
new file mode 100644
index 00000000000..6e08ae0074d
--- /dev/null
+++ b/src/test/compile-fail/union/union-copy.rs
@@ -0,0 +1,26 @@
+// Copyright 2016 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: u8
+}
+
+union W {
+    a: String
+}
+
+impl Clone for U { fn clone(&self) { panic!(); } }
+impl Clone for W { fn clone(&self) { panic!(); } }
+impl Copy for U {} // OK
+impl Copy for W {} //~ ERROR the trait `Copy` may not be implemented for this type
+
+fn main() {}
diff --git a/src/test/compile-fail/union-derive.rs b/src/test/compile-fail/union/union-derive.rs
index 0f78e96f640..0f78e96f640 100644
--- a/src/test/compile-fail/union-derive.rs
+++ b/src/test/compile-fail/union/union-derive.rs
diff --git a/src/test/compile-fail/union-empty.rs b/src/test/compile-fail/union/union-empty.rs
index ce5bbf60fee..ce5bbf60fee 100644
--- a/src/test/compile-fail/union-empty.rs
+++ b/src/test/compile-fail/union/union-empty.rs
diff --git a/src/test/compile-fail/union/union-feature-gate.rs b/src/test/compile-fail/union/union-feature-gate.rs
new file mode 100644
index 00000000000..abfc4d90921
--- /dev/null
+++ b/src/test/compile-fail/union/union-feature-gate.rs
@@ -0,0 +1,15 @@
+// Copyright 2016 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.
+
+union U { //~ ERROR unions are unstable and possibly buggy
+    a: u8,
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/union-fields.rs b/src/test/compile-fail/union/union-fields.rs
index 2bd1b8a7b32..a1721dda7de 100644
--- a/src/test/compile-fail/union-fields.rs
+++ b/src/test/compile-fail/union/union-fields.rs
@@ -24,11 +24,12 @@ fn main() {
     let u = U { ..u }; //~ ERROR union expressions should have exactly one field
                        //~^ ERROR functional record update syntax requires a struct
 
-    let U {} = u; //~ ERROR union patterns without `..` should have at least one field
+    let U {} = u; //~ ERROR union patterns should have exactly one field
     let U { a } = u; // OK
-    let U { a, b } = u; //~ ERROR union patterns can have at most one field
-    let U { a, b, c } = u; //~ ERROR union patterns can have at most one field
+    let U { a, b } = u; //~ ERROR union patterns should have exactly one field
+    let U { a, b, c } = u; //~ ERROR union patterns should have exactly one field
                            //~^ ERROR union `U` does not have a field named `c`
-    let U { .. } = u; // OK
-    let U { a, .. } = u; // OK
+    let U { .. } = u; //~ ERROR union patterns should have exactly one field
+                      //~^ ERROR `..` cannot be used in union patterns
+    let U { a, .. } = u; //~ ERROR `..` cannot be used in union patterns
 }
diff --git a/src/test/compile-fail/union/union-generic.rs b/src/test/compile-fail/union/union-generic.rs
new file mode 100644
index 00000000000..e6586b0fb7f
--- /dev/null
+++ b/src/test/compile-fail/union/union-generic.rs
@@ -0,0 +1,24 @@
+// Copyright 2016 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.
+
+#![feature(untagged_unions)]
+
+use std::rc::Rc;
+
+union U<T: Copy> {
+    a: T
+}
+
+fn main() {
+    let u = U { a: Rc::new(0u32) };
+    //~^ ERROR  the trait bound `std::rc::Rc<u32>: std::marker::Copy` is not satisfied
+    let u = U::<Rc<u32>> { a: Default::default() };
+    //~^ ERROR  the trait bound `std::rc::Rc<u32>: std::marker::Copy` is not satisfied
+}
diff --git a/src/test/compile-fail/union-nonrepresentable.rs b/src/test/compile-fail/union/union-nonrepresentable.rs
index cb4683c2a0e..cb4683c2a0e 100644
--- a/src/test/compile-fail/union-nonrepresentable.rs
+++ b/src/test/compile-fail/union/union-nonrepresentable.rs
diff --git a/src/test/compile-fail/union/union-repr-c.rs b/src/test/compile-fail/union/union-repr-c.rs
new file mode 100644
index 00000000000..d7dfb126c93
--- /dev/null
+++ b/src/test/compile-fail/union/union-repr-c.rs
@@ -0,0 +1,29 @@
+// Copyright 2016 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.
+
+#![feature(untagged_unions)]
+#![allow(unused)]
+#![deny(improper_ctypes)]
+
+#[repr(C)]
+union U {
+    a: u8,
+}
+
+union W {
+    a: u8,
+}
+
+extern "C" {
+    static FOREIGN1: U; // OK
+    static FOREIGN2: W; //~ ERROR found union without foreign-function-safe representation
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/union/union-suggest-field.rs b/src/test/compile-fail/union/union-suggest-field.rs
new file mode 100644
index 00000000000..b05e9b6e273
--- /dev/null
+++ b/src/test/compile-fail/union/union-suggest-field.rs
@@ -0,0 +1,29 @@
+// Copyright 2016 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    principal: u8,
+}
+
+impl U {
+    fn calculate(&self) {}
+}
+
+fn main() {
+    let u = U { principle: 0 }; //~ ERROR union `U` has no field named `principle`
+                                //~^ HELP did you mean `principal`?
+    let w = u.principial; //~ ERROR attempted access of field `principial` on type `U`
+                          //~^ HELP did you mean `principal`?
+
+    let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U`
+                         //~^ HELP maybe a `()` to call it is missing?
+}
diff --git a/src/test/compile-fail/union-unsafe.rs b/src/test/compile-fail/union/union-unsafe.rs
index 762ac5d8751..97e1ec2cba8 100644
--- a/src/test/compile-fail/union-unsafe.rs
+++ b/src/test/compile-fail/union/union-unsafe.rs
@@ -15,9 +15,10 @@ union U {
 }
 
 fn main() {
-    let u = U { a: 10 }; // OK
+    let mut u = U { a: 10 }; // OK
     let a = u.a; //~ ERROR access to union field requires unsafe function or block
+    u.a = 11; //~ ERROR access to union field requires unsafe function or block
     let U { a } = u; //~ ERROR matching on union field requires unsafe function or block
-    if let U { a: 11 } = u {} //~ ERROR matching on union field requires unsafe function or block
-    let U { .. } = u; // OK
+    if let U { a: 12 } = u {} //~ ERROR matching on union field requires unsafe function or block
+    // let U { .. } = u; // OK
 }
diff --git a/src/test/compile-fail/union-unsized.rs b/src/test/compile-fail/union/union-unsized.rs
index 381122406d7..a238eaf0525 100644
--- a/src/test/compile-fail/union-unsized.rs
+++ b/src/test/compile-fail/union/union-unsized.rs
@@ -12,6 +12,12 @@
 
 union U {
     a: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+    b: u8,
+}
+
+union W {
+    a: u8,
+    b: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/union-with-drop-fields-lint.rs b/src/test/compile-fail/union/union-with-drop-fields-lint.rs
index 87a72efbe08..87a72efbe08 100644
--- a/src/test/compile-fail/union-with-drop-fields-lint.rs
+++ b/src/test/compile-fail/union/union-with-drop-fields-lint.rs
diff --git a/src/test/run-pass/auxiliary/union.rs b/src/test/run-pass/union/auxiliary/union.rs
index dc0ca7c81c0..dc0ca7c81c0 100644
--- a/src/test/run-pass/auxiliary/union.rs
+++ b/src/test/run-pass/union/auxiliary/union.rs
diff --git a/src/test/run-pass/union-backcomp.rs b/src/test/run-pass/union/union-backcomp.rs
index c1210dd6212..9394b618ddf 100644
--- a/src/test/run-pass/union-backcomp.rs
+++ b/src/test/run-pass/union/union-backcomp.rs
@@ -10,7 +10,11 @@
 
 #![feature(untagged_unions)]
 
+fn union() {}
+
 fn main() {
+    union();
+
     let union = 10;
 
     union;
diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union/union-basic.rs
index 1651aa901b9..1651aa901b9 100644
--- a/src/test/run-pass/union-basic.rs
+++ b/src/test/run-pass/union/union-basic.rs
diff --git a/src/test/run-pass/union/union-c-interop.rs b/src/test/run-pass/union/union-c-interop.rs
new file mode 100644
index 00000000000..a9f97620ebd
--- /dev/null
+++ b/src/test/run-pass/union/union-c-interop.rs
@@ -0,0 +1,47 @@
+// Copyright 2016 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.
+
+#![feature(untagged_unions)]
+
+#[derive(Copy)]
+#[repr(C)]
+struct LARGE_INTEGER_U {
+    LowPart: u32,
+    HighPart: u32,
+}
+
+#[derive(Copy)]
+#[repr(C)]
+union LARGE_INTEGER {
+  __unnamed__: LARGE_INTEGER_U,
+  u: LARGE_INTEGER_U,
+  QuadPart: u64,
+}
+
+impl Clone for LARGE_INTEGER_U { fn clone(&self) -> Self { *self } }
+impl Clone for LARGE_INTEGER { fn clone(&self) -> Self { *self } }
+
+#[link(name = "rust_test_helpers")]
+extern "C" {
+    fn increment_all_parts(_: LARGE_INTEGER) -> LARGE_INTEGER;
+}
+
+fn main() {
+    unsafe {
+        let mut li = LARGE_INTEGER { QuadPart: 0 };
+        let li_c = increment_all_parts(li);
+        li.__unnamed__.LowPart += 1;
+        li.__unnamed__.HighPart += 1;
+        li.u.LowPart += 1;
+        li.u.HighPart += 1;
+        li.QuadPart += 1;
+        assert_eq!(li.QuadPart, li_c.QuadPart);
+    }
+}
diff --git a/src/test/run-pass/union-const-trans.rs b/src/test/run-pass/union/union-const-trans.rs
index bdae1a0eaf8..bdae1a0eaf8 100644
--- a/src/test/run-pass/union-const-trans.rs
+++ b/src/test/run-pass/union/union-const-trans.rs
diff --git a/src/test/run-pass/union-derive.rs b/src/test/run-pass/union/union-derive.rs
index b71c23990a4..b71c23990a4 100644
--- a/src/test/run-pass/union-derive.rs
+++ b/src/test/run-pass/union/union-derive.rs
diff --git a/src/test/run-pass/union-drop-assign.rs b/src/test/run-pass/union/union-drop-assign.rs
index 0da68e43f32..0da68e43f32 100644
--- a/src/test/run-pass/union-drop-assign.rs
+++ b/src/test/run-pass/union/union-drop-assign.rs
diff --git a/src/test/run-pass/union-drop.rs b/src/test/run-pass/union/union-drop.rs
index 2ca68dc3b6e..2ca68dc3b6e 100644
--- a/src/test/run-pass/union-drop.rs
+++ b/src/test/run-pass/union/union-drop.rs
diff --git a/src/test/run-pass/union/union-generic.rs b/src/test/run-pass/union/union-generic.rs
new file mode 100644
index 00000000000..9293805edbf
--- /dev/null
+++ b/src/test/run-pass/union/union-generic.rs
@@ -0,0 +1,43 @@
+// Copyright 2016 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.
+
+#![feature(untagged_unions)]
+
+union MaybeItem<T: Iterator> {
+    elem: T::Item,
+    none: (),
+}
+
+union U<A, B> {
+    a: A,
+    b: B,
+}
+
+unsafe fn union_transmute<A, B>(a: A) -> B {
+    U { a: a }.b
+}
+
+fn main() {
+    unsafe {
+        let u = U::<String, Vec<u8>> { a: String::from("abcd") };
+
+        assert_eq!(u.b.len(), 4);
+        assert_eq!(u.b[0], b'a');
+
+        let b = union_transmute::<(u8, u8), u16>((1, 1));
+        assert_eq!(b, (1 << 8) + 1);
+
+        let v: Vec<u8> = vec![1, 2, 3];
+        let mut i = v.iter();
+        i.next();
+        let mi = MaybeItem::<std::slice::Iter<_>> { elem: i.next().unwrap() };
+        assert_eq!(*mi.elem, 2);
+    }
+}
diff --git a/src/test/compile-fail/union-field-privacy.rs b/src/test/run-pass/union/union-inherent-method.rs
index d1f2bbbc3d0..adea27bd254 100644
--- a/src/test/compile-fail/union-field-privacy.rs
+++ b/src/test/run-pass/union/union-inherent-method.rs
@@ -10,12 +10,15 @@
 
 #![feature(untagged_unions)]
 
-mod m {
-    pub union U {
-        a: u8
-    }
+union U {
+    a: u8,
+}
+
+impl U {
+    fn method(&self) -> u8 { unsafe { self.a } }
 }
 
 fn main() {
-    let u = m::U { a: 0 }; //~ ERROR field `a` of union `m::U` is private
+    let u = U { a: 10 };
+    assert_eq!(u.method(), 10);
 }
diff --git a/src/test/run-pass/union/union-macro.rs b/src/test/run-pass/union/union-macro.rs
new file mode 100644
index 00000000000..a23fbc3be9e
--- /dev/null
+++ b/src/test/run-pass/union/union-macro.rs
@@ -0,0 +1,33 @@
+// Copyright 2016 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.
+
+#![feature(untagged_unions)]
+
+macro_rules! duplicate {
+   ($i: item) => {
+        mod m1 {
+            $i
+        }
+        mod m2 {
+            $i
+        }
+   }
+}
+
+duplicate! {
+    pub union U {
+        pub a: u8
+    }
+}
+
+fn main() {
+    let u1 = m1::U { a: 0 };
+    let u2 = m2::U { a: 0 };
+}
diff --git a/src/test/run-pass/union/union-overwrite.rs b/src/test/run-pass/union/union-overwrite.rs
new file mode 100644
index 00000000000..9389a6237bc
--- /dev/null
+++ b/src/test/run-pass/union/union-overwrite.rs
@@ -0,0 +1,80 @@
+// Copyright 2016 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.
+
+#![feature(untagged_unions)]
+
+#[repr(C)]
+struct Pair<T, U>(T, U);
+#[repr(C)]
+struct Triple<T>(T, T, T);
+
+#[repr(C)]
+union U<A, B> {
+    a: Pair<A, A>,
+    b: B,
+}
+
+#[repr(C)]
+union W<A, B> {
+    a: A,
+    b: B,
+}
+
+#[cfg(target_endian = "little")]
+unsafe fn check() {
+    let mut u = U::<u8, u16> { b: 0xDE_DE };
+    u.a.0 = 0xBE;
+    assert_eq!(u.b, 0xDE_BE);
+
+    let mut u = U::<u16, u32> { b: 0xDEAD_DEAD };
+    u.a.0 = 0xBEEF;
+    assert_eq!(u.b, 0xDEAD_BEEF);
+
+    let mut u = U::<u32, u64> { b: 0xDEADBEEF_DEADBEEF };
+    u.a.0 = 0xBAADF00D;
+    assert_eq!(u.b, 0xDEADBEEF_BAADF00D);
+
+    let mut w = W::<Pair<Triple<u8>, u8>, u32> { b: 0xDEAD_DEAD };
+    w.a.0 = Triple(0, 0, 0);
+    assert_eq!(w.b, 0xDE00_0000);
+
+    let mut w = W::<Pair<u8, Triple<u8>>, u32> { b: 0xDEAD_DEAD };
+    w.a.1 = Triple(0, 0, 0);
+    assert_eq!(w.b, 0x0000_00AD);
+}
+
+#[cfg(target_endian = "big")]
+unsafe fn check() {
+    let mut u = U::<u8, u16> { b: 0xDE_DE };
+    u.a.0 = 0xBE;
+    assert_eq!(u.b, 0xBE_DE);
+
+    let mut u = U::<u16, u32> { b: 0xDEAD_DEAD };
+    u.a.0 = 0xBEEF;
+    assert_eq!(u.b, 0xBEEF_DEAD);
+
+    let mut u = U::<u32, u64> { b: 0xDEADBEEF_DEADBEEF };
+    u.a.0 = 0xBAADF00D;
+    assert_eq!(u.b, 0xBAADF00D_DEADBEEF);
+
+    let mut w = W::<Pair<Triple<u8>, u8>, u32> { b: 0xDEAD_DEAD };
+    w.a.0 = Triple(0, 0, 0);
+    assert_eq!(w.b, 0x0000_00AD);
+
+    let mut w = W::<Pair<u8, Triple<u8>>, u32> { b: 0xDEAD_DEAD };
+    w.a.1 = Triple(0, 0, 0);
+    assert_eq!(w.b, 0xDE00_0000);
+}
+
+fn main() {
+    unsafe {
+        check();
+    }
+}
diff --git a/src/test/run-pass/union-packed.rs b/src/test/run-pass/union/union-packed.rs
index b1650ae3a7c..6a61280823e 100644
--- a/src/test/run-pass/union-packed.rs
+++ b/src/test/run-pass/union/union-packed.rs
@@ -71,4 +71,34 @@ fn main() {
     assert_eq!(align_of::<Up>(), 1);
     assert_eq!(align_of_val(&up), 1);
     assert_eq!(align_of_val(&CUP), 1);
+
+    hybrid::check_hybrid();
+}
+
+mod hybrid {
+    use std::mem::size_of;
+
+    #[repr(packed)]
+    struct S1 {
+        a: u16,
+        b: u8,
+    }
+
+    #[repr(packed)]
+    union U {
+        s: S1,
+        c: u16,
+    }
+
+    #[repr(packed)]
+    struct S2 {
+        d: u8,
+        u: U,
+    }
+
+    pub fn check_hybrid() {
+        assert_eq!(size_of::<S1>(), 3);
+        assert_eq!(size_of::<U>(), 3);
+        assert_eq!(size_of::<S2>(), 4);
+    }
 }
diff --git a/src/test/run-pass/union-pat-refutability.rs b/src/test/run-pass/union/union-pat-refutability.rs
index e6144f35f1d..e6144f35f1d 100644
--- a/src/test/run-pass/union-pat-refutability.rs
+++ b/src/test/run-pass/union/union-pat-refutability.rs
diff --git a/src/test/run-pass/union/union-trait-impl.rs b/src/test/run-pass/union/union-trait-impl.rs
new file mode 100644
index 00000000000..a5a2be0133a
--- /dev/null
+++ b/src/test/run-pass/union/union-trait-impl.rs
@@ -0,0 +1,27 @@
+// Copyright 2016 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.
+
+#![feature(untagged_unions)]
+
+use std::fmt;
+
+union U {
+    a: u8
+}
+
+impl fmt::Display for U {
+    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        unsafe { write!(f, "Oh hai {}", self.a) }
+    }
+}
+
+fn main() {
+    assert_eq!(U { a: 2 }.to_string(), "Oh hai 2");
+}
diff --git a/src/test/run-pass/union-transmute.rs b/src/test/run-pass/union/union-transmute.rs
index 4eb66268ab8..4eb66268ab8 100644
--- a/src/test/run-pass/union-transmute.rs
+++ b/src/test/run-pass/union/union-transmute.rs
diff --git a/src/test/run-pass/union/union-with-drop-fields-lint.rs b/src/test/run-pass/union/union-with-drop-fields-lint.rs
new file mode 100644
index 00000000000..5a1424830d0
--- /dev/null
+++ b/src/test/run-pass/union/union-with-drop-fields-lint.rs
@@ -0,0 +1,42 @@
+// Copyright 2016 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.
+
+// ignore-pretty
+
+#![feature(untagged_unions)]
+#![allow(dead_code)]
+#![allow(unions_with_drop_fields)]
+
+union U {
+    a: u8, // OK
+}
+
+union W {
+    a: String, // OK
+    b: String, // OK
+}
+
+struct S(String);
+
+// `S` doesn't implement `Drop` trait, but still has non-trivial destructor
+union Y {
+    a: S, // OK
+}
+
+// We don't know if `T` is trivially-destructable or not until trans
+union J<T> {
+    a: T, // OK
+}
+
+union H<T: Copy> {
+    a: T, // OK
+}
+
+fn main() {}
diff --git a/src/test/run-pass/union-xcrate.rs b/src/test/run-pass/union/union-xcrate.rs
index 2a76c96ef25..2a76c96ef25 100644
--- a/src/test/run-pass/union-xcrate.rs
+++ b/src/test/run-pass/union/union-xcrate.rs