about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-08-10 21:00:17 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-09-03 13:39:34 +0300
commit641d8e9e4c12b3753cf4e2a9ac901ad08ea90e00 (patch)
treed58d261fd624fd9248657aad6c7757854752ef5f /src
parenta014323e456c00f93134d03b4af95844b2ed4b95 (diff)
downloadrust-641d8e9e4c12b3753cf4e2a9ac901ad08ea90e00.tar.gz
rust-641d8e9e4c12b3753cf4e2a9ac901ad08ea90e00.zip
Some better support for unions through the compiler
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/check_attr.rs13
-rw-r--r--src/librustc/hir/map/def_collector.rs3
-rw-r--r--src/librustc/infer/error_reporting.rs4
-rw-r--r--src/librustc/middle/dead.rs20
-rw-r--r--src/librustc/middle/expr_use_visitor.rs51
-rw-r--r--src/librustc/middle/stability.rs9
-rw-r--r--src/librustc/traits/coherence.rs2
-rw-r--r--src/librustc/traits/error_reporting.rs1
-rw-r--r--src/librustc/ty/item_path.rs1
-rw-r--r--src/librustc/ty/layout.rs3
-rw-r--r--src/librustc/ty/mod.rs10
-rw-r--r--src/librustc/ty/relate.rs7
-rw-r--r--src/librustc/ty/sty.rs7
-rw-r--r--src/librustc/ty/util.rs17
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs4
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs2
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/move_error.rs1
-rw-r--r--src/librustc_borrowck/borrowck/mir/elaborate_drops.rs4
-rw-r--r--src/librustc_borrowck/borrowck/mir/mod.rs2
-rw-r--r--src/librustc_const_eval/check_match.rs7
-rw-r--r--src/librustc_const_eval/eval.rs3
-rw-r--r--src/librustc_driver/test.rs1
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs1
-rw-r--r--src/librustc_lint/bad_style.rs2
-rw-r--r--src/librustc_lint/builtin.rs17
-rw-r--r--src/librustc_lint/unused.rs1
-rw-r--r--src/librustc_mir/hair/cx/expr.rs5
-rw-r--r--src/librustc_mir/hair/cx/pattern.rs7
-rw-r--r--src/librustc_mir/transform/type_check.rs4
-rw-r--r--src/librustc_passes/consts.rs1
-rw-r--r--src/librustc_privacy/lib.rs10
-rw-r--r--src/librustc_resolve/lib.rs5
-rw-r--r--src/librustc_save_analysis/lib.rs5
-rw-r--r--src/librustc_trans/adt.rs3
-rw-r--r--src/librustc_trans/collector.rs1
-rw-r--r--src/librustc_trans/common.rs6
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs7
-rw-r--r--src/librustc_trans/glue.rs3
-rw-r--r--src/librustc_trans/type_of.rs2
-rw-r--r--src/librustc_typeck/astconv.rs2
-rw-r--r--src/librustc_typeck/check/_match.rs2
-rw-r--r--src/librustc_typeck/check/dropck.rs3
-rw-r--r--src/librustc_typeck/check/method/probe.rs3
-rw-r--r--src/librustc_typeck/check/method/suggest.rs51
-rw-r--r--src/librustc_typeck/check/mod.rs45
-rw-r--r--src/librustc_typeck/check/wfcheck.rs3
-rw-r--r--src/librustc_typeck/coherence/mod.rs3
-rw-r--r--src/librustc_typeck/coherence/orphan.rs7
-rw-r--r--src/librustc_typeck/coherence/overlap.rs2
-rw-r--r--src/librustc_typeck/collect.rs3
-rw-r--r--src/librustc_typeck/variance/constraints.rs1
51 files changed, 243 insertions, 134 deletions
diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index 53624702c84..a2d4239388a 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -18,6 +18,7 @@ use syntax::visit::Visitor;
 enum Target {
     Fn,
     Struct,
+    Union,
     Enum,
     Other,
 }
@@ -27,6 +28,7 @@ impl Target {
         match item.node {
             ast::ItemKind::Fn(..) => Target::Fn,
             ast::ItemKind::Struct(..) => Target::Struct,
+            ast::ItemKind::Union(..) => Target::Union,
             ast::ItemKind::Enum(..) => Target::Enum,
             _ => Target::Other,
         }
@@ -62,8 +64,10 @@ impl<'a> CheckAttrVisitor<'a> {
             let message = match &*name {
                 "C" => {
                     conflicting_reprs += 1;
-                    if target != Target::Struct && target != Target::Enum {
-                        "attribute should be applied to struct or enum"
+                    if target != Target::Struct &&
+                            target != Target::Union &&
+                            target != Target::Enum {
+                        "attribute should be applied to struct, enum or union"
                     } else {
                         continue
                     }
@@ -71,8 +75,9 @@ impl<'a> CheckAttrVisitor<'a> {
                 "packed" => {
                     // Do not increment conflicting_reprs here, because "packed"
                     // can be used to modify another repr hint
-                    if target != Target::Struct {
-                        "attribute should be applied to struct"
+                    if target != Target::Struct &&
+                            target != Target::Union {
+                        "attribute should be applied to struct or union"
                     } else {
                         continue
                     }
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 389d0a1d50d..29fb19fd421 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -331,7 +331,8 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
                         });
                     }
                 }
-                hir::ItemStruct(ref struct_def, _) => {
+                hir::ItemStruct(ref struct_def, _) |
+                hir::ItemUnion(ref struct_def, _) => {
                     // If this is a tuple-like struct, register the constructor.
                     if !struct_def.is_struct() {
                         this.create_def(struct_def.id(),
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 0cd39882b7c..efce0c8354b 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -105,6 +105,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             match item.node {
                 hir::ItemImpl(..) => "impl",
                 hir::ItemStruct(..) => "struct",
+                hir::ItemUnion(..) => "union",
                 hir::ItemEnum(..) => "enum",
                 hir::ItemTrait(..) => "trait",
                 hir::ItemFn(..) => "function body",
@@ -1370,7 +1371,8 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
                 }
                 hir::TyPath(ref maybe_qself, ref path) => {
                     match self.tcx.expect_def(cur_ty.id) {
-                        Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
+                        Def::Enum(did) | Def::TyAlias(did) |
+                        Def::Struct(did) | Def::Union(did) => {
                             let generics = self.tcx.lookup_generics(did);
 
                             let expected =
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 824383b11af..9a63ad4b985 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -86,7 +86,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
     }
 
     fn lookup_and_handle_definition(&mut self, id: ast::NodeId) {
-        use ty::TypeVariants::{TyEnum, TyStruct};
+        use ty::TypeVariants::{TyEnum, TyStruct, TyUnion};
 
         let def = self.tcx.expect_def(id);
 
@@ -96,7 +96,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
             if self.tcx.trait_of_item(def.def_id()).is_some() => {
                 if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) {
                     match substs.substs.type_at(0).sty {
-                        TyEnum(tyid, _) | TyStruct(tyid, _) => {
+                        TyEnum(tyid, _) | TyStruct(tyid, _) | TyUnion(tyid, _) => {
                             self.check_def_id(tyid.did)
                         }
                         _ => {}
@@ -132,10 +132,11 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
     }
 
     fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) {
-        if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty {
-            self.insert_def_id(def.struct_variant().field_named(name).did);
-        } else {
-            span_bug!(lhs.span, "named field access on non-struct")
+        match self.tcx.expr_ty_adjusted(lhs).sty {
+            ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
+                self.insert_def_id(def.struct_variant().field_named(name).did);
+            }
+            _ => span_bug!(lhs.span, "named field access on non-struct"),
         }
     }
 
@@ -148,7 +149,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
     fn handle_field_pattern_match(&mut self, lhs: &hir::Pat,
                                   pats: &[codemap::Spanned<hir::FieldPat>]) {
         let variant = match self.tcx.node_id_to_type(lhs.id).sty {
-            ty::TyStruct(adt, _) | ty::TyEnum(adt, _) => {
+            ty::TyStruct(adt, _) | ty::TyUnion(adt, _) | ty::TyEnum(adt, _) => {
                 adt.variant_of_def(self.tcx.expect_def(lhs.id))
             }
             _ => span_bug!(lhs.span, "non-ADT in struct pattern")
@@ -185,7 +186,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
         match *node {
             ast_map::NodeItem(item) => {
                 match item.node {
-                    hir::ItemStruct(..) => {
+                    hir::ItemStruct(..) | hir::ItemUnion(..) => {
                         self.struct_has_extern_repr = item.attrs.iter().any(|attr| {
                             attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr)
                                 .contains(&attr::ReprExtern)
@@ -423,7 +424,8 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
             | hir::ItemConst(..)
             | hir::ItemFn(..)
             | hir::ItemEnum(..)
-            | hir::ItemStruct(..) => true,
+            | hir::ItemStruct(..)
+            | hir::ItemUnion(..) => true,
             _ => false
         };
         let ctor_id = get_struct_ctor_id(item);
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 798702e6fd6..7214049f6cd 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -672,30 +672,36 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
         // Select just those fields of the `with`
         // expression that will actually be used
-        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);
+        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);
+                    }
                 }
             }
-        } 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");
+            ty::TyUnion(..) => {
+                unimplemented_unions!();
             }
-        };
+            _ => {
+                // 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");
+                }
+            }
+        }
 
         // walk the with expression so that complex expressions
         // are properly handled.
@@ -1012,7 +1018,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                     debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat);
                     delegate.matched_pat(pat, downcast_cmt, match_mode);
                 }
-                Some(Def::Struct(..)) | Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => {
+                Some(Def::Struct(..)) | Some(Def::Union(..)) |
+                Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => {
                     debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat);
                     delegate.matched_pat(pat, cmt_pat, match_mode);
                 }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index c20fcc3fe1d..e6979c25453 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -561,7 +561,9 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
         hir::ExprField(ref base_e, ref field) => {
             span = field.span;
             match tcx.expr_ty_adjusted(base_e).sty {
-                ty::TyStruct(def, _) => def.struct_variant().field_named(field.node).did,
+                ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
+                    def.struct_variant().field_named(field.node).did
+                }
                 _ => span_bug!(e.span,
                                "stability::check_expr: named field access on non-struct")
             }
@@ -579,7 +581,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
         hir::ExprStruct(_, ref expr_fields, _) => {
             let type_ = tcx.expr_ty(e);
             match type_.sty {
-                ty::TyStruct(def, _) => {
+                ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
                     // check the stability of each field that appears
                     // in the construction expression.
                     for field in expr_fields {
@@ -647,7 +649,8 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat,
     if is_internal(tcx, pat.span) { return; }
 
     let v = match tcx.pat_ty_opt(pat) {
-        Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) => def.struct_variant(),
+        Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) |
+        Some(&ty::TyS { sty: ty::TyUnion(def, _), .. }) => def.struct_variant(),
         Some(_) | None => return,
     };
     match pat.node {
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index f856e110ea2..0a7d3e6e76d 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -224,7 +224,7 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool {
     match ty.sty {
         ty::TyBox(..) | ty::TyRef(..) =>
             true,
-        ty::TyEnum(def, _) | ty::TyStruct(def, _) =>
+        ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) =>
             def.is_fundamental(),
         ty::TyTrait(ref data) =>
             tcx.has_attr(data.principal.def_id(), "fundamental"),
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 95e83d404a7..e5ebe96932d 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -174,6 +174,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         match (type_category(a), type_category(b)) {
             (Some(cat_a), Some(cat_b)) => match (&a.sty, &b.sty) {
                 (&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) |
+                (&ty::TyUnion(def_a, _), &ty::TyUnion(def_b, _)) |
                 (&ty::TyEnum(def_a, _), &ty::TyEnum(def_b, _)) =>
                     def_a == def_b,
                 _ => cat_a == cat_b
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index 42ec2b18fb0..ba8d3328509 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -263,6 +263,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // anything other than a simple path.
         match self_ty.sty {
             ty::TyStruct(adt_def, substs) |
+            ty::TyUnion(adt_def, substs) |
             ty::TyEnum(adt_def, substs) => {
                 if substs.types().next().is_none() { // ignore regions
                     self.push_item_path(buffer, adt_def.did);
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 622966ca5ab..ac5e3c6fa70 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -1256,6 +1256,9 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
                 }
             }
 
+            ty::TyUnion(..) => {
+                unimplemented_unions!();
+            }
             ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
                 // Only newtypes and enums w/ nullable pointer optimization.
                 if def.variants.is_empty() || def.variants.len() > 2 {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 4cda7491113..ee2188e8e11 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -948,6 +948,7 @@ impl<'tcx> TraitPredicate<'tcx> {
                 .flat_map(|t| t.walk())
                 .filter_map(|t| match t.sty {
                     ty::TyStruct(adt_def, _) |
+                    ty::TyUnion(adt_def, _) |
                     ty::TyEnum(adt_def, _) =>
                         Some(adt_def.did),
                     _ =>
@@ -1341,6 +1342,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                     }
                     hir::ItemEnum(..) |
                     hir::ItemStruct(..) |
+                    hir::ItemUnion(..) |
                     hir::ItemTy(..) |
                     hir::ItemImpl(..) |
                     hir::ItemConst(..) |
@@ -1615,7 +1617,8 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
     /// Asserts this is a struct and returns the struct's unique
     /// variant.
     pub fn struct_variant(&self) -> &VariantDefData<'gcx, 'container> {
-        assert_eq!(self.adt_kind(), AdtKind::Struct);
+        let adt_kind = self.adt_kind();
+        assert!(adt_kind == AdtKind::Struct || adt_kind == AdtKind::Union);
         &self.variants[0]
     }
 
@@ -1674,7 +1677,8 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
     pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'gcx, 'container> {
         match def {
             Def::Variant(_, vid) => self.variant_with_id(vid),
-            Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(),
+            Def::Struct(..) | Def::Union(..) |
+            Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(),
             _ => bug!("unexpected def {:?} in variant_of_def", def)
         }
     }
@@ -2413,7 +2417,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             Def::Variant(enum_did, did) => {
                 self.lookup_adt_def(enum_did).variant_with_id(did)
             }
-            Def::Struct(did) => {
+            Def::Struct(did) | Def::Union(did) => {
                 self.lookup_adt_def(did).struct_variant()
             }
             _ => bug!("expect_variant_def used with unexpected def {:?}", def)
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 5c157ff32e7..dfae19487b6 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -447,6 +447,13 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
             Ok(tcx.mk_struct(a_def, substs))
         }
 
+        (&ty::TyUnion(a_def, a_substs), &ty::TyUnion(b_def, b_substs))
+            if a_def == b_def =>
+        {
+            let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?;
+            Ok(tcx.mk_union(a_def, substs))
+        }
+
         (&ty::TyClosure(a_id, a_substs),
          &ty::TyClosure(b_id, b_substs))
             if a_id == b_id =>
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index b023cdad9ee..165f86fbef5 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -922,7 +922,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
         // FIXME(#24885): be smarter here, the AdtDefData::is_empty method could easily be made
         // more complete.
         match self.sty {
-            TyEnum(def, _) | TyStruct(def, _) => def.is_empty(),
+            TyEnum(def, _) | TyStruct(def, _) | TyUnion(def, _) => def.is_empty(),
 
             // FIXME(canndrew): There's no reason why these can't be uncommented, they're tested
             // and they don't break anything. But I'm keeping my changes small for now.
@@ -985,7 +985,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
 
     pub fn is_structural(&self) -> bool {
         match self.sty {
-            TyStruct(..) | TyTuple(_) | TyEnum(..) |
+            TyStruct(..) | TyUnion(..) | TyTuple(..) | TyEnum(..) |
             TyArray(..) | TyClosure(..) => true,
             _ => self.is_slice() | self.is_trait()
         }
@@ -1204,6 +1204,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
         match self.sty {
             TyTrait(ref tt) => Some(tt.principal.def_id()),
             TyStruct(def, _) |
+            TyUnion(def, _) |
             TyEnum(def, _) => Some(def.did),
             TyClosure(id, _) => Some(id),
             _ => None
@@ -1212,7 +1213,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
 
     pub fn ty_adt_def(&self) -> Option<AdtDef<'tcx>> {
         match self.sty {
-            TyStruct(adt, _) | TyEnum(adt, _) => Some(adt),
+            TyStruct(adt, _) | TyUnion(adt, _) | TyEnum(adt, _) => Some(adt),
             _ => None
         }
     }
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 971fc2cee80..ad209094600 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -138,7 +138,7 @@ impl<'tcx> ParameterEnvironment<'tcx> {
         // FIXME: (@jroesch) float this code up
         tcx.infer_ctxt(None, Some(self.clone()), Reveal::ExactMatch).enter(|infcx| {
             let adt = match self_type.sty {
-                ty::TyStruct(struct_def, substs) => {
+                ty::TyStruct(struct_def, substs) | ty::TyUnion(struct_def, substs) => {
                     for field in struct_def.all_fields() {
                         let field_ty = field.ty(tcx, substs);
                         if infcx.type_moves_by_default(field_ty, span) {
@@ -183,7 +183,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn has_error_field(self, ty: Ty<'tcx>) -> bool {
         match ty.sty {
-            ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
+            ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => {
                 for field in def.all_fields() {
                     let field_ty = field.ty(self, substs);
                     if let TyError = field_ty.sty {
@@ -203,7 +203,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                                  i: usize,
                                  variant: Option<DefId>) -> Option<Ty<'tcx>> {
         match (&ty.sty, variant) {
-            (&TyStruct(def, substs), None) => {
+            (&TyStruct(def, substs), None) |
+            (&TyUnion(def, substs), None) => {
                 def.struct_variant().fields.get(i).map(|f| f.ty(self, substs))
             }
             (&TyEnum(def, substs), Some(vid)) => {
@@ -225,7 +226,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                             n: Name,
                             variant: Option<DefId>) -> Option<Ty<'tcx>> {
         match (&ty.sty, variant) {
-            (&TyStruct(def, substs), None) => {
+            (&TyStruct(def, substs), None) |
+            (&TyUnion(def, substs), None)  => {
                 def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs))
             }
             (&TyEnum(def, substs), Some(vid)) => {
@@ -661,7 +663,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
                 TyArray(ty, _) => {
                     is_type_structurally_recursive(tcx, sp, seen, ty)
                 }
-                TyStruct(def, substs) | TyEnum(def, substs) => {
+                TyStruct(def, substs) | TyUnion(def, substs) | TyEnum(def, substs) => {
                     find_nonrepresentable(tcx,
                                           sp,
                                           seen,
@@ -678,7 +680,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
 
         fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool {
             match ty.sty {
-                TyStruct(ty_def, _) | TyEnum(ty_def, _) => {
+                TyStruct(ty_def, _) | TyUnion(ty_def, _) | TyEnum(ty_def, _) => {
                      ty_def == def
                 }
                 _ => false
@@ -688,6 +690,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
         fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
             match (&a.sty, &b.sty) {
                 (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) |
+                (&TyUnion(did_a, ref substs_a), &TyUnion(did_b, ref substs_b)) |
                 (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => {
                     if did_a != did_b {
                         return false;
@@ -710,7 +713,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
             debug!("is_type_structurally_recursive: {:?}", ty);
 
             match ty.sty {
-                TyStruct(def, _) | TyEnum(def, _) => {
+                TyStruct(def, _) | TyUnion(def, _) | TyEnum(def, _) => {
                     {
                         // Iterate through stack of previously seen types.
                         let mut iter = seen.iter();
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index e86fa9a05f3..b4c6689c24b 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -796,7 +796,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
             }
             LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => {
                 match lp_base.to_type().sty {
-                    ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => {
+                    ty::TyStruct(def, _) |
+                    ty::TyUnion(def, _) |
+                    ty::TyEnum(def, _) if def.has_dtor() => {
                         // In the case where the owner implements drop, then
                         // the path must be initialized to prevent a case of
                         // partial reinitialization
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index 9431dcdbcac..3cf02fc85a4 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -178,7 +178,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         Categorization::Interior(ref b, mc::InteriorField(_)) |
         Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
             match b.ty.sty {
-                ty::TyStruct(def, _) | ty::TyEnum(def, _) => {
+                ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => {
                     if def.has_dtor() {
                         Some(cmt.clone())
                     } else {
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
index fc17633d63b..61c85e393d2 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
@@ -149,6 +149,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         Categorization::Interior(ref b, mc::InteriorField(_)) => {
             match b.ty.sty {
                 ty::TyStruct(def, _) |
+                ty::TyUnion(def, _) |
                 ty::TyEnum(def, _) if def.has_dtor() => {
                     let mut err = struct_span_err!(bccx, move_from.span, E0509,
                                                    "cannot move out of type `{}`, \
diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index 885bbe856c8..c5d10345379 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -709,7 +709,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
     fn open_drop<'a>(&mut self, c: &DropCtxt<'a, 'tcx>) -> BasicBlock {
         let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
         match ty.sty {
-            ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
+            ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => {
                 self.open_drop_for_adt(c, def, substs)
             }
             ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts {
@@ -893,7 +893,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
 
         match ty.sty {
-            ty::TyStruct(def, _) | ty::TyEnum(def, _) => {
+            ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => {
                 if def.has_dtor() {
                     self.tcx.sess.span_warn(
                         c.source_info.span,
diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs
index 887c7deb86b..be408e2db5c 100644
--- a/src/librustc_borrowck/borrowck/mir/mod.rs
+++ b/src/librustc_borrowck/borrowck/mir/mod.rs
@@ -261,7 +261,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
                    lv, ty);
             true
         }
-        ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => {
+        ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) if def.has_dtor() => {
             debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => false",
                    lv, ty);
             true
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index e71a780dd89..de28cbb7c9c 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -566,7 +566,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
     let pat = match left_ty.sty {
         ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None),
 
-        ty::TyEnum(adt, _) | ty::TyStruct(adt, _)  => {
+        ty::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => {
             let v = ctor.variant_for_adt(adt);
             match v.kind {
                 VariantKind::Struct => {
@@ -792,7 +792,8 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
         PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) =>
             match cx.tcx.expect_def(pat.id) {
                 Def::Variant(_, id) => vec![Variant(id)],
-                Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single],
+                Def::Struct(..) | Def::Union(..) |
+                Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single],
                 Def::Const(..) | Def::AssociatedConst(..) =>
                     span_bug!(pat.span, "const pattern should've been rewritten"),
                 def => span_bug!(pat.span, "pat_constructors: unexpected definition {:?}", def),
@@ -836,7 +837,7 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us
             _ => bug!()
         },
         ty::TyRef(..) => 1,
-        ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
+        ty::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => {
             ctor.variant_for_adt(adt).fields.len()
         }
         ty::TyArray(_, n) => n,
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index d71add3258f..81fe19812ca 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -258,7 +258,8 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 format!("floating point constants cannot be used in patterns"));
         }
         ty::TyEnum(adt_def, _) |
-        ty::TyStruct(adt_def, _) => {
+        ty::TyStruct(adt_def, _) |
+        ty::TyUnion(adt_def, _) => {
             if !tcx.has_attr(adt_def.did, "structural_match") {
                 tcx.sess.add_lint(
                     lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 460a6e68a5c..9f5f82c144c 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -220,6 +220,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
 
                 hir::ItemEnum(..) |
                 hir::ItemStruct(..) |
+                hir::ItemUnion(..) |
                 hir::ItemTrait(..) |
                 hir::ItemImpl(..) |
                 hir::ItemDefaultImpl(..) => {
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index c1158dc2d5f..d4a3ab59f9c 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -419,6 +419,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
             Def::AssociatedTy(..) |
             Def::TyParam(..) |
             Def::Struct(..) |
+            Def::Union(..) |
             Def::Trait(..) |
             Def::Method(..) |
             Def::Const(..) |
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 0e130c3bb66..1094d0ee12b 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -111,7 +111,7 @@ impl LateLintPass for NonCamelCaseTypes {
         }
 
         match it.node {
-            hir::ItemTy(..) | hir::ItemStruct(..) => {
+            hir::ItemTy(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => {
                 self.check_case(cx, "type", it.name, it.span)
             }
             hir::ItemTrait(..) => {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index a103386e2c9..571d1222baa 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -116,7 +116,8 @@ impl LateLintPass for BoxPointers {
             hir::ItemFn(..) |
             hir::ItemTy(..) |
             hir::ItemEnum(..) |
-            hir::ItemStruct(..) =>
+            hir::ItemStruct(..) |
+            hir::ItemUnion(..) =>
                 self.check_heap_type(cx, it.span,
                                      cx.tcx.node_id_to_type(it.id)),
             _ => ()
@@ -124,7 +125,8 @@ impl LateLintPass for BoxPointers {
 
         // If it's a struct, we also have to check the fields' types
         match it.node {
-            hir::ItemStruct(ref struct_def, _) => {
+            hir::ItemStruct(ref struct_def, _) |
+            hir::ItemUnion(ref struct_def, _) => {
                 for struct_field in struct_def.fields() {
                     self.check_heap_type(cx, struct_field.span,
                                          cx.tcx.node_id_to_type(struct_field.id));
@@ -348,6 +350,7 @@ impl LateLintPass for MissingDoc {
             hir::ItemMod(..) => "a module",
             hir::ItemEnum(..) => "an enum",
             hir::ItemStruct(..) => "a struct",
+            hir::ItemUnion(..) => "a union",
             hir::ItemTrait(_, _, _, ref items) => {
                 // Issue #11592, traits are always considered exported, even when private.
                 if it.vis == hir::Visibility::Inherited {
@@ -467,6 +470,14 @@ impl LateLintPass for MissingCopyImplementations {
                 let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id));
                 (def, cx.tcx.mk_struct(def, Substs::empty(cx.tcx)))
             }
+            hir::ItemUnion(_, ref ast_generics) => {
+                if ast_generics.is_parameterized() {
+                    return;
+                }
+                let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id));
+                (def, cx.tcx.mk_union(def,
+                                      cx.tcx.mk_substs(Substs::empty())))
+            }
             hir::ItemEnum(_, ref ast_generics) => {
                 if ast_generics.is_parameterized() {
                     return;
@@ -523,7 +534,7 @@ impl LateLintPass for MissingDebugImplementations {
         }
 
         match item.node {
-            hir::ItemStruct(..) | hir::ItemEnum(..) => {},
+            hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemEnum(..) => {},
             _ => return,
         }
 
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 924b768958d..44f1cf7b533 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -137,6 +137,7 @@ impl LateLintPass for UnusedResults {
             ty::TyNever => return,
             ty::TyBool => return,
             ty::TyStruct(def, _) |
+            ty::TyUnion(def, _) |
             ty::TyEnum(def, _) => {
                 let attrs = cx.tcx.get_attrs(def.did);
                 check_must_use(cx, &attrs[..], s.span)
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 6e8a5771eea..0469d44de4b 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -477,6 +477,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         })
                     }
                 }
+                ty::TyUnion(..) => {
+                    unimplemented_unions!();
+                }
                 ty::TyEnum(adt, substs) => {
                     match cx.tcx.expect_def(expr.id) {
                         Def::Variant(enum_id, variant_id) => {
@@ -579,7 +582,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                              body: block::to_expr_ref(cx, body) },
         hir::ExprField(ref source, name) => {
             let index = match cx.tcx.expr_ty_adjusted(source).sty {
-                ty::TyStruct(adt_def, _) =>
+                ty::TyStruct(adt_def, _) | ty::TyUnion(adt_def, _) =>
                     adt_def.variants[0].index_of_field_named(name.node),
                 ref ty =>
                     span_bug!(
diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs
index 0bd22cd2d93..30f79796aaa 100644
--- a/src/librustc_mir/hair/cx/pattern.rs
+++ b/src/librustc_mir/hair/cx/pattern.rs
@@ -217,7 +217,9 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
             PatKind::Struct(_, ref fields, _) => {
                 let pat_ty = self.cx.tcx.node_id_to_type(pat.id);
                 let adt_def = match pat_ty.sty {
-                    ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def,
+                    ty::TyStruct(adt_def, _) |
+                    ty::TyUnion(adt_def, _) |
+                    ty::TyEnum(adt_def, _) => adt_def,
                     _ => {
                         span_bug!(
                             pat.span,
@@ -313,7 +315,8 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
                 }
             }
 
-            Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => {
+            Def::Struct(..) | Def::Union(..) |
+            Def::TyAlias(..) | Def::AssociatedTy(..) => {
                 PatternKind::Leaf { subpatterns: subpatterns }
             }
 
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 21d4ae595e8..55bd51cd75b 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -281,7 +281,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                 (&adt_def.variants[variant_index], substs)
             }
             LvalueTy::Ty { ty } => match ty.sty {
-                ty::TyStruct(adt_def, substs) | ty::TyEnum(adt_def, substs)
+                ty::TyStruct(adt_def, substs) |
+                ty::TyUnion(adt_def, substs) |
+                ty::TyEnum(adt_def, substs)
                     if adt_def.is_univariant() => {
                         (&adt_def.variants[0], substs)
                     }
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 2d1b6e1315f..c3749bf4546 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -440,6 +440,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
 fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
     match node_ty.sty {
         ty::TyStruct(def, _) |
+        ty::TyUnion(def, _) |
         ty::TyEnum(def, _) if def.has_dtor() => {
             v.add_qualif(ConstQualif::NEEDS_DROP);
         }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index cd2eb4d2b58..25601b6bfec 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -174,7 +174,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
                     self.update(trait_item.id, item_level);
                 }
             }
-            hir::ItemStruct(ref def, _) => {
+            hir::ItemStruct(ref def, _) | hir::ItemUnion(ref def, _) => {
                 if !def.is_struct() {
                     self.update(def.id(), item_level);
                 }
@@ -321,8 +321,8 @@ impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<
         if let hir::TyPath(_, ref path) = ty.node {
             let def = self.ev.tcx.expect_def(ty.id);
             match def {
-                Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
-                Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
+                Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) |
+                Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
                     if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
                         let item = self.ev.tcx.map.expect_item(node_id);
                         if let Def::TyAlias(..) = def {
@@ -943,8 +943,8 @@ impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a,
                     // free type aliases, but this isn't done yet.
                     return
                 }
-                Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
-                Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
+                Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) |
+                Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
                     // Non-local means public (private items can't leave their crate, modulo bugs)
                     if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
                         let item = self.tcx.map.expect_item(node_id);
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 1224c694a4e..db0704db33f 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -2187,6 +2187,7 @@ impl<'a> Resolver<'a> {
                                         Def::Trait(_) |
                                         Def::Enum(_) |
                                         Def::Struct(_) |
+                                        Def::Union(_) |
                                         Def::TyAlias(_) => true,
                                         _               => false,
                                     },
@@ -2389,7 +2390,7 @@ impl<'a> Resolver<'a> {
                 PatKind::Struct(ref path, _, _) => {
                     self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| {
                         match def {
-                            Def::Struct(..) | Def::Variant(..) |
+                            Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
                             Def::TyAlias(..) | Def::AssociatedTy(..) => true,
                             _ => false,
                         }
@@ -2735,7 +2736,7 @@ impl<'a> Resolver<'a> {
             // Look for a field with the same name in the current self_type.
             if let Some(resolution) = self.def_map.get(&node_id) {
                 match resolution.base_def {
-                    Def::Enum(did) | Def::TyAlias(did) |
+                    Def::Enum(did) | Def::TyAlias(did) | Def::Union(did) |
                     Def::Struct(did) | Def::Variant(_, did) if resolution.depth == 0 => {
                         if let Some(fields) = self.structs.get(&did) {
                             if fields.iter().any(|&field_name| name == field_name) {
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index db535e22f19..47f3a06de1b 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -404,7 +404,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     }
                 };
                 match self.tcx.expr_ty_adjusted(&hir_node).sty {
-                    ty::TyStruct(def, _) => {
+                    ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
                         let f = def.struct_variant().field_named(ident.node.name);
                         let sub_span = self.span_utils.span_for_last_ident(expr.span);
                         filter!(self.span_utils, sub_span, expr.span, None);
@@ -423,7 +423,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             }
             ast::ExprKind::Struct(ref path, _, _) => {
                 match self.tcx.expr_ty_adjusted(&hir_node).sty {
-                    ty::TyStruct(def, _) => {
+                    ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
                         let sub_span = self.span_utils.span_for_last_ident(path.span);
                         filter!(self.span_utils, sub_span, path.span, None);
                         Some(Data::TypeRefData(TypeRefData {
@@ -487,6 +487,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 }))
             }
             Def::Struct(def_id) |
+            Def::Union(def_id) |
             Def::Enum(def_id) |
             Def::TyAlias(def_id) |
             Def::Trait(def_id) |
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 2fb7a69d361..069eef7895c 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -176,6 +176,9 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
             Univariant(mk_struct(cx, &ftys[..], packed, t))
         }
+        ty::TyUnion(..) => {
+            unimplemented_unions!();
+        }
         ty::TyClosure(_, ref substs) => {
             Univariant(mk_struct(cx, &substs.upvar_tys, false, t))
         }
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 47b3bb36cb9..4bea5d7e87f 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -744,6 +744,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     // monomorphized Drop::drop() implementation.
     let destructor_did = match ty.sty {
         ty::TyStruct(def, _) |
+        ty::TyUnion(def, _) |
         ty::TyEnum(def, _)   => def.destructor(),
         _ => None
     };
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index f4682de7dff..6ae6f8aead7 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -88,8 +88,8 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
         return false;
     }
     match ty.sty {
-        ty::TyStruct(..) | ty::TyEnum(..) | ty::TyTuple(..) | ty::TyArray(_, _) |
-        ty::TyClosure(..) => {
+        ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) |
+        ty::TyTuple(..) | ty::TyArray(..) | ty::TyClosure(..) => {
             let llty = sizing_type_of(ccx, ty);
             llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type())
         }
@@ -205,7 +205,7 @@ impl<'a, 'tcx> VariantInfo<'tcx> {
                    -> Self
     {
         match ty.sty {
-            ty::TyStruct(adt, substs) | ty::TyEnum(adt, substs) => {
+            ty::TyStruct(adt, substs) | ty::TyUnion(adt, substs) | ty::TyEnum(adt, substs) => {
                 let variant = match opt_def {
                     None => adt.struct_variant(),
                     Some(def) => adt.variant_of_def(def)
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 67d4a0e044c..f30880ac9be 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -184,6 +184,10 @@ impl<'tcx> TypeMap<'tcx> {
                 unique_type_id.push_str("struct ");
                 from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id);
             },
+            ty::TyUnion(def, substs) => {
+                unique_type_id.push_str("union ");
+                from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id);
+            },
             ty::TyTuple(component_types) if component_types.is_empty() => {
                 push_debuginfo_type_name(cx, type_, false, &mut unique_type_id);
             },
@@ -781,6 +785,9 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                     unique_type_id,
                                     usage_site_span).finalize(cx)
         }
+        ty::TyUnion(..) => {
+            unimplemented_unions!();
+        }
         ty::TyTuple(ref elements) => {
             prepare_tuple_metadata(cx,
                                    t,
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 9e1e415f62a..5da9ef3646e 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -470,6 +470,9 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
                 trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None)
             }
         }
+        ty::TyUnion(..) => {
+            unimplemented_unions!();
+        }
         ty::TyTrait(..) => {
             // No support in vtable for distinguishing destroying with
             // versus without calling Drop::drop. Assert caller is
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index d5d8f049681..b5565109306 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -331,7 +331,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
 
     // If this was an enum or struct, fill in the type now.
     match t.sty {
-        ty::TyEnum(..) | ty::TyStruct(..) | ty::TyClosure(..)
+        ty::TyEnum(..) | ty::TyStruct(..) | ty::TyUnion(..) | ty::TyClosure(..)
                 if !t.is_simd() => {
             let repr = adt::represent_type(cx, t);
             adt::finish_type_of(cx, &repr, &mut llty);
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 6c9cc5f5e13..c445455ef2b 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1476,7 +1476,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                                span,
                                                partition_bounds(tcx, span, &[]))
             }
-            Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
+            Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => {
                 tcx.prohibit_type_params(base_segments.split_last().unwrap().1);
                 self.ast_path_to_ty(rscope,
                                     span,
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index f8a2e82edc2..5fdfa19190b 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -510,7 +510,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Type check subpatterns.
         let substs = match pat_ty.sty {
-            ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
+            ty::TyStruct(_, substs) | ty::TyUnion(_, substs) | ty::TyEnum(_, substs) => substs,
             _ => span_bug!(pat.span, "struct variant is not an ADT")
         };
         self.check_struct_pat_fields(pat.span, fields, variant, substs, etc);
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index bd47ff0b00b..3e37602169a 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -45,6 +45,7 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()>
     let dtor_predicates = ccx.tcx.lookup_predicates(drop_impl_did);
     match dtor_self_type.sty {
         ty::TyEnum(adt_def, self_to_impl_substs) |
+        ty::TyUnion(adt_def, self_to_impl_substs) |
         ty::TyStruct(adt_def, self_to_impl_substs) => {
             ensure_drop_params_and_item_params_correspond(ccx,
                                                           drop_impl_did,
@@ -495,7 +496,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
 fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                         ty: Ty<'tcx>) -> bool {
     match ty.sty {
-        ty::TyEnum(def, _) | ty::TyStruct(def, _) => {
+        ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
             def.is_dtorck(tcx)
         }
         ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 2e2cb2765d9..edee7300868 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -293,7 +293,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                 self.assemble_inherent_impl_candidates_for_type(data.principal.def_id());
             }
             ty::TyEnum(def, _) |
-            ty::TyStruct(def, _) => {
+            ty::TyStruct(def, _) |
+            ty::TyUnion(def, _) => {
                 self.assemble_inherent_impl_candidates_for_type(def.did);
             }
             ty::TyBox(_) => {
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 46b3f503b6e..6d8a73b8a6a 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -164,30 +164,33 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // give a helping note that it has to be called as (x.f)(...).
                 if let Some(expr) = rcvr_expr {
                     for (ty, _) in self.autoderef(span, rcvr_ty) {
-                        if let ty::TyStruct(def, substs) = ty.sty {
-                            if let Some(field) = def.struct_variant().find_field_named(item_name) {
-                                let snippet = tcx.sess.codemap().span_to_snippet(expr.span);
-                                let expr_string = match snippet {
-                                    Ok(expr_string) => expr_string,
-                                    _ => "s".into() // Default to a generic placeholder for the
-                                                    // expression when we can't generate a
-                                                    // string snippet
-                                };
-
-                                let field_ty = field.ty(tcx, substs);
-
-                                if self.is_fn_ty(&field_ty, span) {
-                                    err.span_note(span, &format!(
-                                        "use `({0}.{1})(...)` if you meant to call the function \
-                                         stored in the `{1}` field",
-                                        expr_string, item_name));
-                                } else {
-                                    err.span_note(span, &format!(
-                                        "did you mean to write `{0}.{1}`?",
-                                        expr_string, item_name));
+                        match ty.sty {
+                            ty::TyStruct(def, substs) | ty::TyUnion(def, substs) => {
+                                if let Some(field) = def.struct_variant().find_field_named(item_name) {
+                                    let snippet = tcx.sess.codemap().span_to_snippet(expr.span);
+                                    let expr_string = match snippet {
+                                        Ok(expr_string) => expr_string,
+                                        _ => "s".into() // Default to a generic placeholder for the
+                                                        // expression when we can't generate a
+                                                        // string snippet
+                                    };
+
+                                    let field_ty = field.ty(tcx, substs);
+
+                                    if self.is_fn_ty(&field_ty, span) {
+                                        err.span_note(span, &format!(
+                                            "use `({0}.{1})(...)` if you meant to call the function \
+                                             stored in the `{1}` field",
+                                            expr_string, item_name));
+                                    } else {
+                                        err.span_note(span, &format!(
+                                            "did you mean to write `{0}.{1}`?",
+                                            expr_string, item_name));
+                                    }
+                                    break;
                                 }
-                                break;
                             }
+                            _ => {}
                         }
                     }
                 }
@@ -355,7 +358,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             rcvr_expr: Option<&hir::Expr>) -> bool {
         fn is_local(ty: Ty) -> bool {
             match ty.sty {
-                ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.did.is_local(),
+                ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
+                    def.did.is_local()
+                }
 
                 ty::TyTrait(ref tr) => tr.principal.def_id().is_local(),
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index be33f836cc6..679ced1987e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -762,6 +762,9 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
       hir::ItemStruct(..) => {
         check_struct(ccx, it.id, it.span);
       }
+      hir::ItemUnion(..) => {
+        unimplemented_unions!();
+      }
       hir::ItemTy(_, ref generics) => {
         let pty_ty = ccx.tcx.node_id_to_type(it.id);
         check_bounds_are_used(ccx, generics, pty_ty);
@@ -2942,18 +2945,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let mut private_candidate = None;
         let mut autoderef = self.autoderef(expr.span, expr_t);
         while let Some((base_t, autoderefs)) = autoderef.next() {
-            if let ty::TyStruct(base_def, substs) = base_t.sty {
-                debug!("struct named {:?}",  base_t);
-                if let Some(field) = base_def.struct_variant().find_field_named(field.node) {
-                    let field_ty = self.field_ty(expr.span, field, substs);
-                    if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
-                        autoderef.finalize(lvalue_pref, Some(base));
-                        self.write_ty(expr.id, field_ty);
-                        self.write_autoderef_adjustment(base.id, autoderefs);
-                        return;
+            match base_t.sty {
+                ty::TyStruct(base_def, substs) | ty::TyUnion(base_def, substs) => {
+                    debug!("struct named {:?}",  base_t);
+                    if let Some(field) = base_def.struct_variant().find_field_named(field.node) {
+                        let field_ty = self.field_ty(expr.span, field, substs);
+                        if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
+                            autoderef.finalize(lvalue_pref, Some(base));
+                            self.write_ty(expr.id, field_ty);
+                            self.write_autoderef_adjustment(base.id, autoderefs);
+                            return;
+                        }
+                        private_candidate = Some((base_def.did, field_ty));
                     }
-                    private_candidate = Some((base_def.did, field_ty));
                 }
+                _ => {}
             }
         }
         autoderef.unambiguous_final_ty();
@@ -2986,12 +2992,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          but no field with that name was found",
                         field.node, actual)
             }, expr_t);
-            if let ty::TyRawPtr(..) = expr_t.sty {
-                err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \
-                                  `(*{0}).{1}`", pprust::expr_to_string(base), field.node));
-            }
-            if let ty::TyStruct(def, _) = expr_t.sty {
-                Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
+            match expr_t.sty {
+                ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
+                    Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
+                }
+                ty::TyRawPtr(..) => {
+                    err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \
+                                      `(*{0}).{1}`", pprust::expr_to_string(base), field.node));
+                }
+                _ => {}
             }
             err.emit();
             self.write_error(expr.id);
@@ -3125,7 +3134,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                 check_completeness: bool) {
         let tcx = self.tcx;
         let substs = match adt_ty.sty {
-            ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
+            ty::TyStruct(_, substs) | ty::TyUnion(_, substs) | ty::TyEnum(_, substs) => substs,
             _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields")
         };
 
@@ -3217,7 +3226,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.set_tainted_by_errors();
                 return None;
             }
-            Def::Variant(type_did, _) | Def::Struct(type_did) => {
+            Def::Variant(type_did, _) | Def::Struct(type_did) | Def::Union(type_did) => {
                 Some((type_did, self.tcx.expect_variant_def(def)))
             }
             Def::TyAlias(did) => {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 435442bd30a..19bee13b6f6 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -142,6 +142,9 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
 
                 self.check_variances_for_type_defn(item, ast_generics);
             }
+            hir::ItemUnion(..) => {
+                unimplemented_unions!();
+            }
             hir::ItemEnum(ref enum_def, ref ast_generics) => {
                 self.check_type_defn(item, |fcx| {
                     fcx.enum_variants(enum_def)
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index a20195bd801..fba145efa95 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -242,7 +242,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
             let self_type = tcx.lookup_item_type(impl_did);
             match self_type.ty.sty {
                 ty::TyEnum(type_def, _) |
-                ty::TyStruct(type_def, _) => {
+                ty::TyStruct(type_def, _) |
+                ty::TyUnion(type_def, _) => {
                     type_def.set_destructor(method_def_id.def_id());
                 }
                 _ => {
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index bcce64cb110..4c38475335c 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -76,7 +76,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
                 let self_ty = self.tcx.lookup_item_type(def_id).ty;
                 match self_ty.sty {
                     ty::TyEnum(def, _) |
-                    ty::TyStruct(def, _) => {
+                    ty::TyStruct(def, _) |
+                    ty::TyUnion(def, _) => {
                         self.check_def_id(item, def.did);
                     }
                     ty::TyTrait(ref data) => {
@@ -293,7 +294,9 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
                 {
                     let self_ty = trait_ref.self_ty();
                     let opt_self_def_id = match self_ty.sty {
-                        ty::TyStruct(self_def, _) | ty::TyEnum(self_def, _) =>
+                        ty::TyStruct(self_def, _) |
+                        ty::TyUnion(self_def, _) |
+                        ty::TyEnum(self_def, _) =>
                             Some(self_def.did),
                         ty::TyBox(..) =>
                             self.tcx.lang_items.owned_box(),
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index f60fb9583a6..c4d925372f1 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -97,7 +97,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
 impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v hir::Item) {
         match item.node {
-            hir::ItemEnum(..) | hir::ItemStruct(..) => {
+            hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => {
                 let type_def_id = self.tcx.map.local_def_id(item.id);
                 self.check_for_overlapping_inherent_impls(type_def_id);
             }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 7f9de2becee..1d260b9dbb2 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -931,7 +931,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             tcx.trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
                                                        trait_item_def_ids);
         },
-        hir::ItemStruct(ref struct_def, _) => {
+        hir::ItemStruct(ref struct_def, _) |
+        hir::ItemUnion(ref struct_def, _) => {
             let def_id = ccx.tcx.map.local_def_id(it.id);
             let scheme = type_scheme_of_def_id(ccx, def_id);
             let predicates = predicates_of_item(ccx, it);
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index e20e74be67c..24eb29f45a5 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -185,6 +185,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                         hir::ItemTy(..) |
                         hir::ItemEnum(..) |
                         hir::ItemStruct(..) |
+                        hir::ItemUnion(..) |
                         hir::ItemTrait(..)   => is_inferred = true,
                         hir::ItemFn(..)      => is_inferred = false,
                         _                    => cannot_happen!(),