about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-08-07 01:09:00 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-09-03 13:37:25 +0300
commitcbd912babab4b8cebe9e90a632117913ca192743 (patch)
tree4e59815e06c47d9c278a575f8634de4066025145
parent35d52a003bf0997d31378796bf59cc66c3ae7683 (diff)
downloadrust-cbd912babab4b8cebe9e90a632117913ca192743.tar.gz
rust-cbd912babab4b8cebe9e90a632117913ca192743.zip
Add union types
-rw-r--r--src/librustc/infer/freshen.rs1
-rw-r--r--src/librustc/traits/coherence.rs3
-rw-r--r--src/librustc/traits/error_reporting.rs1
-rw-r--r--src/librustc/traits/select.rs7
-rw-r--r--src/librustc/ty/contents.rs3
-rw-r--r--src/librustc/ty/context.rs4
-rw-r--r--src/librustc/ty/error.rs3
-rw-r--r--src/librustc/ty/fast_reject.rs3
-rw-r--r--src/librustc/ty/flags.rs2
-rw-r--r--src/librustc/ty/item_path.rs1
-rw-r--r--src/librustc/ty/layout.rs3
-rw-r--r--src/librustc/ty/mod.rs3
-rw-r--r--src/librustc/ty/outlives.rs1
-rw-r--r--src/librustc/ty/structural_impls.rs2
-rw-r--r--src/librustc/ty/sty.rs6
-rw-r--r--src/librustc/ty/util.rs5
-rw-r--r--src/librustc/ty/walk.rs1
-rw-r--r--src/librustc/ty/wf.rs3
-rw-r--r--src/librustc/util/ppaux.rs5
-rw-r--r--src/librustc_lint/types.rs34
-rw-r--r--src/librustc_metadata/tyencode.rs5
-rw-r--r--src/librustc_trans/collector.rs1
-rw-r--r--src/librustc_trans/debuginfo/type_names.rs1
-rw-r--r--src/librustc_trans/trans_item.rs1
-rw-r--r--src/librustc_trans/type_of.rs83
-rw-r--r--src/librustc_typeck/check/dropck.rs2
-rw-r--r--src/librustc_typeck/coherence/mod.rs5
-rw-r--r--src/librustc_typeck/variance/constraints.rs3
-rw-r--r--src/librustdoc/clean/mod.rs1
29 files changed, 124 insertions, 69 deletions
diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs
index f793d489cab..8aeb0757f5d 100644
--- a/src/librustc/infer/freshen.rs
+++ b/src/librustc/infer/freshen.rs
@@ -168,6 +168,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
             ty::TyFnPtr(_) |
             ty::TyTrait(..) |
             ty::TyStruct(..) |
+            ty::TyUnion(..) |
             ty::TyClosure(..) |
             ty::TyNever |
             ty::TyTuple(..) |
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index a5a415dd27c..f856e110ea2 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -261,7 +261,8 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)->
         }
 
         ty::TyEnum(def, _) |
-        ty::TyStruct(def, _) => {
+        ty::TyStruct(def, _) |
+        ty::TyUnion(def, _) => {
             def.did.is_local()
         }
 
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 6d6d7c2b3ba..95e83d404a7 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -166,6 +166,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 ty::TyParam(..) => Some(14),
                 ty::TyAnon(..) => Some(15),
                 ty::TyNever => Some(16),
+                ty::TyUnion(..) => Some(17),
                 ty::TyInfer(..) | ty::TyError => None
             }
         }
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 0573f0c5bba..f8f10d9c265 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1780,7 +1780,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 Where(ty::Binder(tys.last().into_iter().cloned().collect()))
             }
 
-            ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
+            ty::TyStruct(def, substs) | ty::TyUnion(def, substs) |
+            ty::TyEnum(def, substs) => {
                 let sized_crit = def.sized_constraint(self.tcx());
                 // (*) binder moved here
                 Where(ty::Binder(match sized_crit.sty {
@@ -1836,7 +1837,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 Where(ty::Binder(tys.to_vec()))
             }
 
-            ty::TyStruct(..) | ty::TyEnum(..) |
+            ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) |
             ty::TyProjection(..) | ty::TyParam(..) | ty::TyAnon(..) => {
                 // Fallback to whatever user-defined impls exist in this case.
                 None
@@ -1933,7 +1934,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 substs.types().collect()
             }
 
-            ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
+            ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => {
                 def.all_fields()
                     .map(|f| f.ty(self.tcx(), substs))
                     .collect()
diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs
index 53bf046d6b5..d7d4693c116 100644
--- a/src/librustc/ty/contents.rs
+++ b/src/librustc/ty/contents.rs
@@ -224,7 +224,8 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
                                         |ty| tc_ty(tcx, *ty, cache))
                 }
 
-                ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
+                ty::TyStruct(def, substs) | ty::TyUnion(def, substs) |
+                ty::TyEnum(def, substs) => {
                     let mut res =
                         TypeContents::union(&def.variants, |v| {
                             TypeContents::union(&v.fields, |f| {
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 725bbf6adfd..8dd7bc562d7 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1032,8 +1032,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
     pub fn print_debug_stats(self) {
         sty_debug_print!(
             self,
-            TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr,
-            TyTrait, TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
+            TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyTrait,
+            TyStruct, TyUnion, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
 
         println!("Substs interner: #{}", self.interners.substs.borrow().len());
         println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len());
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 3d60d326b2b..0e33e396f7e 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -247,6 +247,9 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
             ty::TyStruct(def, _) => {
                 format!("struct `{}`", tcx.item_path_str(def.did))
             }
+            ty::TyUnion(def, _) => {
+                format!("union `{}`", tcx.item_path_str(def.did))
+            }
             ty::TyClosure(..) => "closure".to_string(),
             ty::TyTuple(_) => "tuple".to_string(),
             ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(),
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index f7472d611be..23678d1e377 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -66,6 +66,9 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         ty::TyStruct(def, _) => {
             Some(StructSimplifiedType(def.did))
         }
+        ty::TyUnion(..) => {
+            unimplemented_unions!();
+        }
         ty::TyRef(_, mt) => {
             // since we introduce auto-refs during method lookup, we
             // just treat &T and T as equivalent from the point of
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index 1afd49ab47f..ce6e4d6516e 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -102,7 +102,7 @@ impl FlagComputation {
                 }
             }
 
-            &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) => {
+            &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) | &ty::TyUnion(_, substs) => {
                 self.add_substs(substs);
             }
 
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index 62bd30e2555..42ec2b18fb0 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -320,6 +320,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> {
     match ty.sty {
         ty::TyStruct(adt_def, _) |
+        ty::TyUnion(adt_def, _) |
         ty::TyEnum(adt_def, _) => Some(adt_def.did),
 
         ty::TyTrait(ref data) => Some(data.principal.def_id()),
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 1ede8545e08..622966ca5ab 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -896,6 +896,9 @@ impl<'a, 'gcx, 'tcx> Layout {
                     non_zero: Some(def.did) == tcx.lang_items.non_zero()
                 }
             }
+            ty::TyUnion(..) => {
+                unimplemented_unions!();
+            }
             ty::TyEnum(def, substs) => {
                 let hint = *tcx.lookup_repr_hints(def.did).get(0)
                     .unwrap_or(&attr::ReprAny);
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index e9c01f5bad6..ddf25538ee4 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1421,6 +1421,7 @@ bitflags! {
         const IS_PHANTOM_DATA     = 1 << 3,
         const IS_SIMD             = 1 << 4,
         const IS_FUNDAMENTAL      = 1 << 5,
+        const IS_UNION            = 1 << 7,
     }
 }
 
@@ -1818,7 +1819,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> {
                 }
             }
 
-            TyEnum(adt, substs) | TyStruct(adt, substs) => {
+            TyEnum(adt, substs) | TyStruct(adt, substs) | TyUnion(adt, substs) => {
                 // recursive case
                 let adt = tcx.lookup_adt_def_master(adt.did);
                 adt.calculate_sized_constraint_inner(tcx, stack);
diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs
index 4d5b38212f6..a7bb0374b75 100644
--- a/src/librustc/ty/outlives.rs
+++ b/src/librustc/ty/outlives.rs
@@ -174,6 +174,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             ty::TyNever |           // ...
             ty::TyEnum(..) |        // OutlivesNominalType
             ty::TyStruct(..) |      // OutlivesNominalType
+            ty::TyUnion(..) |      // OutlivesNominalType
             ty::TyBox(..) |         // OutlivesNominalType (ish)
             ty::TyAnon(..) |        // OutlivesNominalType (ish)
             ty::TyStr |             // OutlivesScalar (ish)
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index ad3769605ab..952641f6832 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -495,6 +495,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
                 ty::TyRef(r.fold_with(folder), tm.fold_with(folder))
             }
             ty::TyStruct(did, substs) => ty::TyStruct(did, substs.fold_with(folder)),
+            ty::TyUnion(did, substs) => ty::TyUnion(did, substs.fold_with(folder)),
             ty::TyClosure(did, substs) => ty::TyClosure(did, substs.fold_with(folder)),
             ty::TyProjection(ref data) => ty::TyProjection(data.fold_with(folder)),
             ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)),
@@ -524,6 +525,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
             ty::TyFnPtr(ref f) => f.visit_with(visitor),
             ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor),
             ty::TyStruct(_did, ref substs) => substs.visit_with(visitor),
+            ty::TyUnion(_did, ref substs) => substs.visit_with(visitor),
             ty::TyClosure(_did, ref substs) => substs.visit_with(visitor),
             ty::TyProjection(ref data) => data.visit_with(visitor),
             ty::TyAnon(_, ref substs) => substs.visit_with(visitor),
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 0e3f18c4474..b023cdad9ee 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -120,6 +120,11 @@ pub enum TypeVariants<'tcx> {
     /// See warning about substitutions for enumerated types.
     TyStruct(AdtDef<'tcx>, &'tcx Substs<'tcx>),
 
+    /// A union type, defined with `union`.
+    ///
+    /// See warning about substitutions for enumerated types.
+    TyUnion(AdtDef<'tcx>, &'tcx Substs<'tcx>),
+
     /// `Box<T>`; this is nominally a struct in the documentation, but is
     /// special-cased internally. For example, it is possible to implicitly
     /// move the contents of a box out of that box, and methods of any type
@@ -1227,6 +1232,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
             }
             TyEnum(_, substs) |
             TyStruct(_, substs) |
+            TyUnion(_, substs) |
             TyAnon(_, substs) => {
                 substs.regions().collect()
             }
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 77d16287fed..971fc2cee80 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -430,6 +430,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> {
             TyUint(u) => self.hash(u),
             TyFloat(f) => self.hash(f),
             TyStruct(d, _) |
+            TyUnion(d, _) |
             TyEnum(d, _) => self.def_id(d.did),
             TyArray(_, n) => self.hash(n),
             TyRawPtr(m) |
@@ -558,7 +559,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
             }) => Some(true),
 
             TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) |
-            TyClosure(..) | TyEnum(..) | TyStruct(..) | TyAnon(..) |
+            TyClosure(..) | TyEnum(..) | TyStruct(..) | TyUnion(..) | TyAnon(..) |
             TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None
         }.unwrap_or_else(|| !self.impls_bound(tcx, param_env, ty::BoundCopy, span));
 
@@ -598,7 +599,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
 
             TyStr | TyTrait(..) | TySlice(_) => Some(false),
 
-            TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) |
+            TyEnum(..) | TyStruct(..) | TyUnion(..) | TyProjection(..) | TyParam(..) |
             TyInfer(..) | TyAnon(..) | TyError => None
         }.unwrap_or_else(|| self.impls_bound(tcx, param_env, ty::BoundSized, span));
 
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index 409f5a85997..cea3bd6348d 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -95,6 +95,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
         }
         ty::TyEnum(_, ref substs) |
         ty::TyStruct(_, ref substs) |
+        ty::TyUnion(_, ref substs) |
         ty::TyAnon(_, ref substs) => {
             stack.extend(substs.types().rev());
         }
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index aef646a7aac..599e2be4db2 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -337,7 +337,8 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
                 }
 
                 ty::TyEnum(def, substs) |
-                ty::TyStruct(def, substs) => {
+                ty::TyStruct(def, substs) |
+                ty::TyUnion(def, substs) => {
                     // WfNominalType
                     let obligations = self.nominal_obligations(def.did, substs);
                     self.out.extend(obligations);
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 7e2cc2938ca..d0e02f2e8ac 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -8,11 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
 use hir::def_id::DefId;
 use ty::subst::{self, Subst, Substs};
 use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
-use ty::{TyBool, TyChar, TyStruct, TyEnum};
+use ty::{TyBool, TyChar, TyStruct, TyUnion, TyEnum};
 use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
 use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
 use ty::TyClosure;
@@ -869,7 +868,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
             TyInfer(infer_ty) => write!(f, "{}", infer_ty),
             TyError => write!(f, "[type error]"),
             TyParam(ref param_ty) => write!(f, "{}", param_ty),
-            TyEnum(def, substs) | TyStruct(def, substs) => {
+            TyEnum(def, substs) | TyStruct(def, substs) | TyUnion(def, substs) => {
                 ty::tls::with(|tcx| {
                     if def.did.is_local() &&
                           !tcx.tcache.borrow().contains_key(&def.did) {
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 40e78c007cc..54cec3fd7e1 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -377,7 +377,8 @@ enum FfiResult {
     FfiSafe,
     FfiUnsafe(&'static str),
     FfiBadStruct(DefId, &'static str),
-    FfiBadEnum(DefId, &'static str)
+    FfiBadUnion(DefId, &'static str),
+    FfiBadEnum(DefId, &'static str),
 }
 
 /// Check if this enum can be safely exported based on the
@@ -452,12 +453,32 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     let r = self.check_type_for_ffi(cache, field_ty);
                     match r {
                         FfiSafe => {}
-                        FfiBadStruct(..) | FfiBadEnum(..) => { return r; }
+                        FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
                         FfiUnsafe(s) => { return FfiBadStruct(def.did, s); }
                     }
                 }
                 FfiSafe
             }
+            ty::TyUnion(def, substs) => {
+                if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+                    return FfiUnsafe(
+                        "found union without foreign-function-safe \
+                         representation annotation in foreign module, \
+                         consider adding a #[repr(C)] attribute to \
+                         the type");
+                }
+
+                for field in &def.struct_variant().fields {
+                    let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
+                    let r = self.check_type_for_ffi(cache, field_ty);
+                    match r {
+                        FfiSafe => {}
+                        FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
+                        FfiUnsafe(s) => { return FfiBadUnion(def.did, s); }
+                    }
+                }
+                FfiSafe
+            }
             ty::TyEnum(def, substs) => {
                 if def.variants.is_empty() {
                     // Empty enums are okay... although sort of useless.
@@ -507,7 +528,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         let r = self.check_type_for_ffi(cache, arg);
                         match r {
                             FfiSafe => {}
-                            FfiBadStruct(..) | FfiBadEnum(..) => { return r; }
+                            FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
                             FfiUnsafe(s) => { return FfiBadEnum(def.did, s); }
                         }
                     }
@@ -614,6 +635,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     &format!("found non-foreign-function-safe member in \
                               struct marked #[repr(C)]: {}", s));
             }
+            FfiResult::FfiBadUnion(_, s) => {
+                // FIXME: This diagnostic is difficult to read, and doesn't
+                // point at the relevant field.
+                self.cx.span_lint(IMPROPER_CTYPES, sp,
+                    &format!("found non-foreign-function-safe member in \
+                              union marked #[repr(C)]: {}", s));
+            }
             FfiResult::FfiBadEnum(_, s) => {
                 // FIXME: This diagnostic is difficult to read, and doesn't
                 // point at the relevant variant.
diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs
index 954ca878c01..b334a21c07c 100644
--- a/src/librustc_metadata/tyencode.rs
+++ b/src/librustc_metadata/tyencode.rs
@@ -170,6 +170,11 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx
             enc_substs(w, cx, substs);
             write!(w, "]");
         }
+        ty::TyUnion(def, substs) => {
+            write!(w, "u[{}|", (cx.ds)(cx.tcx, def.did));
+            enc_substs(w, cx, substs);
+            write!(w, "]");
+        }
         ty::TyClosure(def, substs) => {
             write!(w, "k[{}|", (cx.ds)(cx.tcx, def));
             enc_substs(w, cx, substs.func_substs);
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index bea6f30faec..47b3bb36cb9 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -798,6 +798,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             /* nothing to do */
         }
         ty::TyStruct(ref adt_def, substs) |
+        ty::TyUnion(ref adt_def, substs) |
         ty::TyEnum(ref adt_def, substs) => {
             for field in adt_def.all_fields() {
                 let field_type = monomorphize::apply_param_substs(scx,
diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs
index f757578e695..bd839243e20 100644
--- a/src/librustc_trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/debuginfo/type_names.rs
@@ -45,6 +45,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()),
         ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()),
         ty::TyStruct(def, substs) |
+        ty::TyUnion(def, substs) |
         ty::TyEnum(def, substs) => {
             push_item_name(cx, def.did, qualified, output);
             push_type_params(cx, substs, output);
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 8a0f37230c8..deef0b09a17 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -397,6 +397,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"),
         ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"),
         ty::TyStruct(adt_def, substs) |
+        ty::TyUnion(adt_def, substs) |
         ty::TyEnum(adt_def, substs) => {
             push_item_name(tcx, adt_def.did, output);
             push_type_params(tcx, substs, &[], output);
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 6605d12e2e1..d5d8f049681 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -89,27 +89,23 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
             Type::nil(cx)
         }
 
-        ty::TyTuple(..) | ty::TyEnum(..) | ty::TyClosure(..) => {
-            let repr = adt::represent_type(cx, t);
-            adt::sizing_type_of(cx, &repr, false)
+        ty::TyStruct(..) if t.is_simd() => {
+            let e = t.simd_type(cx.tcx());
+            if !e.is_machine() {
+                cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
+                                          a non-machine element type `{}`",
+                                         t, e))
+            }
+            let llet = type_of(cx, e);
+            let n = t.simd_size(cx.tcx()) as u64;
+            ensure_array_fits_in_address_space(cx, llet, n, t);
+            Type::vector(&llet, n)
         }
 
-        ty::TyStruct(..) => {
-            if t.is_simd() {
-                let e = t.simd_type(cx.tcx());
-                if !e.is_machine() {
-                    cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
-                                              a non-machine element type `{}`",
-                                             t, e))
-                }
-                let llet = type_of(cx, e);
-                let n = t.simd_size(cx.tcx()) as u64;
-                ensure_array_fits_in_address_space(cx, llet, n, t);
-                Type::vector(&llet, n)
-            } else {
-                let repr = adt::represent_type(cx, t);
-                adt::sizing_type_of(cx, &repr, false)
-            }
+        ty::TyTuple(..) | ty::TyStruct(..) | ty::TyUnion(..) |
+        ty::TyEnum(..) | ty::TyClosure(..) => {
+            let repr = adt::represent_type(cx, t);
+            adt::sizing_type_of(cx, &repr, false)
         }
 
         ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) |
@@ -244,15 +240,6 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
       ty::TyUint(t) => Type::uint_from_ty(cx, t),
       ty::TyFloat(t) => Type::float_from_ty(cx, t),
       ty::TyNever => Type::nil(cx),
-      ty::TyEnum(def, ref substs) => {
-          // Only create the named struct, but don't fill it in. We
-          // fill it in *after* placing it into the type cache. This
-          // avoids creating more than one copy of the enum when one
-          // of the enum's variants refers to the enum itself.
-          let repr = adt::represent_type(cx, t);
-          let name = llvm_type_name(cx, def.did, substs);
-          adt::incomplete_type_of(cx, &repr, &name[..])
-      }
       ty::TyClosure(..) => {
           // Only create the named struct, but don't fill it in. We
           // fill it in *after* placing it into the type cache.
@@ -307,26 +294,28 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
           let repr = adt::represent_type(cx, t);
           adt::type_of(cx, &repr)
       }
-      ty::TyStruct(def, ref substs) => {
-          if t.is_simd() {
-              let e = t.simd_type(cx.tcx());
-              if !e.is_machine() {
-                  cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
-                                            a non-machine element type `{}`",
-                                           t, e))
-              }
-              let llet = in_memory_type_of(cx, e);
-              let n = t.simd_size(cx.tcx()) as u64;
-              ensure_array_fits_in_address_space(cx, llet, n, t);
-              Type::vector(&llet, n)
-          } else {
-              // Only create the named struct, but don't fill it in. We fill it
-              // in *after* placing it into the type cache. This prevents
-              // infinite recursion with recursive struct types.
-              let repr = adt::represent_type(cx, t);
-              let name = llvm_type_name(cx, def.did, substs);
-              adt::incomplete_type_of(cx, &repr, &name[..])
+      ty::TyStruct(..) if t.is_simd() => {
+          let e = t.simd_type(cx.tcx());
+          if !e.is_machine() {
+              cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
+                                        a non-machine element type `{}`",
+                                       t, e))
           }
+          let llet = in_memory_type_of(cx, e);
+          let n = t.simd_size(cx.tcx()) as u64;
+          ensure_array_fits_in_address_space(cx, llet, n, t);
+          Type::vector(&llet, n)
+      }
+      ty::TyStruct(def, ref substs) |
+      ty::TyUnion(def, ref substs) |
+      ty::TyEnum(def, ref substs) => {
+          // Only create the named struct, but don't fill it in. We
+          // fill it in *after* placing it into the type cache. This
+          // avoids creating more than one copy of the enum when one
+          // of the enum's variants refers to the enum itself.
+          let repr = adt::represent_type(cx, t);
+          let name = llvm_type_name(cx, def.did, substs);
+          adt::incomplete_type_of(cx, &repr, &name[..])
       }
 
       ty::TyInfer(..) |
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 3a607677433..b73b8b99887 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -439,7 +439,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
                 cx, context, ity, depth+1)
         }
 
-        ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
+        ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => {
             let did = def.did;
             for variant in &def.variants {
                 for field in variant.fields.iter() {
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index f743ef21875..a20195bd801 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -24,7 +24,7 @@ use rustc::ty::{ImplOrTraitItemId, ConstTraitItemId};
 use rustc::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
 use rustc::ty::{Ty, TyBool, TyChar, TyEnum, TyError};
 use rustc::ty::{TyParam, TyRawPtr};
-use rustc::ty::{TyRef, TyStruct, TyTrait, TyNever, TyTuple};
+use rustc::ty::{TyRef, TyStruct, TyUnion, TyTrait, TyNever, TyTuple};
 use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
 use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr};
 use rustc::ty::{TyProjection, TyAnon};
@@ -70,7 +70,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
     fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
         match ty.sty {
             TyEnum(def, _) |
-            TyStruct(def, _) => {
+            TyStruct(def, _) |
+            TyUnion(def, _) => {
                 Some(def.did)
             }
 
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 888709d2572..e20e74be67c 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -344,7 +344,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             }
 
             ty::TyEnum(def, substs) |
-            ty::TyStruct(def, substs) => {
+            ty::TyStruct(def, substs) |
+            ty::TyUnion(def, substs) => {
                 let item_type = self.tcx().lookup_item_type(def.did);
 
                 // This edge is actually implied by the call to
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e4b6a30d5bc..92bb265ca99 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1801,6 +1801,7 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
                 decl: (cx.map.local_def_id(0), &fty.sig).clean(cx),
                 abi: fty.abi,
             }),
+            ty::TyUnion(..) => unimplemented_unions!(),
             ty::TyStruct(def, substs) |
             ty::TyEnum(def, substs) => {
                 let did = def.did;