about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-03-24 21:26:57 +0000
committerbors <bors@rust-lang.org>2019-03-24 21:26:57 +0000
commit3752b3d3a56bf3eabb588b7d595cd1f8accc0286 (patch)
treecb3574e7525a5eb9deb097ff8af38da1581b8d6b /src
parent0576ac109b1ee40cc3201ac3c9ed58339487140e (diff)
parent23cae1d3f06ccb339f2f780e63b6d6d5c1c6a9da (diff)
downloadrust-3752b3d3a56bf3eabb588b7d595cd1f8accc0286.tar.gz
rust-3752b3d3a56bf3eabb588b7d595cd1f8accc0286.zip
Auto merge of #59382 - davidtwco:rfc-2008-refactoring, r=petrochenkov
Separate `DefId`s for variants and their constructors

Part of #44109. Split off from #59376. See [Zulip topic](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/rfc-2008/near/132663140) for previous discussion.

r? @petrochenkov
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/def.rs37
-rw-r--r--src/librustc/hir/intravisit.rs5
-rw-r--r--src/librustc/hir/lowering.rs20
-rw-r--r--src/librustc/hir/map/collector.rs14
-rw-r--r--src/librustc/hir/map/def_collector.rs18
-rw-r--r--src/librustc/hir/map/definitions.rs8
-rw-r--r--src/librustc/hir/map/mod.rs39
-rw-r--r--src/librustc/hir/mod.rs66
-rw-r--r--src/librustc/hir/pat_util.rs8
-rw-r--r--src/librustc/hir/print.rs67
-rw-r--r--src/librustc/lint/context.rs6
-rw-r--r--src/librustc/lint/mod.rs2
-rw-r--r--src/librustc/middle/dead.rs41
-rw-r--r--src/librustc/middle/expr_use_visitor.rs16
-rw-r--r--src/librustc/middle/mem_categorization.rs23
-rw-r--r--src/librustc/middle/reachable.rs2
-rw-r--r--src/librustc/middle/stability.rs17
-rw-r--r--src/librustc/mir/mod.rs2
-rw-r--r--src/librustc/traits/error_reporting.rs24
-rw-r--r--src/librustc/ty/inhabitedness/mod.rs29
-rw-r--r--src/librustc/ty/instance.rs4
-rw-r--r--src/librustc/ty/mod.rs180
-rw-r--r--src/librustc/ty/print/pretty.rs22
-rw-r--r--src/librustc/ty/util.rs4
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs3
-rw-r--r--src/librustc_codegen_utils/symbol_names.rs2
-rw-r--r--src/librustc_lint/builtin.rs2
-rw-r--r--src/librustc_metadata/cstore_impl.rs8
-rw-r--r--src/librustc_metadata/decoder.rs65
-rw-r--r--src/librustc_metadata/encoder.rs99
-rw-r--r--src/librustc_metadata/schema.rs9
-rw-r--r--src/librustc_mir/borrow_check/mod.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs4
-rw-r--r--src/librustc_mir/build/matches/simplify.rs2
-rw-r--r--src/librustc_mir/build/mod.rs5
-rw-r--r--src/librustc_mir/hair/cx/expr.rs26
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs35
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs14
-rw-r--r--src/librustc_mir/shim.rs2
-rw-r--r--src/librustc_mir/util/pretty.rs8
-rw-r--r--src/librustc_passes/ast_validation.rs2
-rw-r--r--src/librustc_passes/rvalue_promotion.rs7
-rw-r--r--src/librustc_privacy/lib.rs77
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs21
-rw-r--r--src/librustc_resolve/error_reporting.rs5
-rw-r--r--src/librustc_resolve/lib.rs21
-rw-r--r--src/librustc_resolve/resolve_imports.rs5
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs13
-rw-r--r--src/librustc_save_analysis/lib.rs26
-rw-r--r--src/librustc_save_analysis/sig.rs7
-rw-r--r--src/librustc_typeck/astconv.rs19
-rw-r--r--src/librustc_typeck/check/_match.rs17
-rw-r--r--src/librustc_typeck/check/demand.rs2
-rw-r--r--src/librustc_typeck/check/method/mod.rs9
-rw-r--r--src/librustc_typeck/check/mod.rs22
-rw-r--r--src/librustc_typeck/collect.rs139
-rw-r--r--src/librustc_typeck/variance/constraints.rs4
-rw-r--r--src/librustc_typeck/variance/mod.rs2
-rw-r--r--src/librustc_typeck/variance/terms.rs4
-rw-r--r--src/librustdoc/clean/inline.rs4
-rw-r--r--src/librustdoc/clean/mod.rs23
-rw-r--r--src/librustdoc/doctree.rs1
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs4
-rw-r--r--src/librustdoc/visit_ast.rs9
-rw-r--r--src/libsyntax/ast.rs48
-rw-r--r--src/libsyntax/config.rs5
-rw-r--r--src/libsyntax/ext/build.rs1
-rw-r--r--src/libsyntax/mut_visit.rs7
-rw-r--r--src/libsyntax/parse/parser.rs11
-rw-r--r--src/libsyntax/print/pprust.rs74
-rw-r--r--src/libsyntax_ext/deriving/debug.rs96
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs8
-rw-r--r--src/test/mir-opt/unusual-item-types.rs4
73 files changed, 859 insertions, 780 deletions
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index b45fc3ffd82..3cc23ccdb64 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -9,6 +9,15 @@ use crate::ty;
 
 use self::Namespace::*;
 
+/// Encodes if a `Def::Ctor` is the constructor of an enum variant or a struct.
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, HashStable)]
+pub enum CtorOf {
+    /// This `Def::Ctor` is a synthesized constructor of a tuple or unit struct.
+    Struct,
+    /// This `Def::Ctor` is a synthesized constructor of a tuple or unit variant.
+    Variant,
+}
+
 #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, HashStable)]
 pub enum CtorKind {
     /// Constructor function automatically created by a tuple struct/variant.
@@ -37,9 +46,11 @@ pub enum NonMacroAttrKind {
 pub enum Def {
     // Type namespace
     Mod(DefId),
-    Struct(DefId), // `DefId` refers to `NodeId` of the struct itself
+    /// `DefId` refers to the struct itself, `Def::Ctor` refers to its constructor if it exists.
+    Struct(DefId),
     Union(DefId),
     Enum(DefId),
+    /// `DefId` refers to the variant itself, `Def::Ctor` refers to its constructor if it exists.
     Variant(DefId),
     Trait(DefId),
     /// `existential type Foo: Bar;`
@@ -61,8 +72,8 @@ pub enum Def {
     Const(DefId),
     ConstParam(DefId),
     Static(DefId, bool /* is_mutbl */),
-    StructCtor(DefId, CtorKind), // `DefId` refers to `NodeId` of the struct's constructor
-    VariantCtor(DefId, CtorKind), // `DefId` refers to the enum variant
+    /// `DefId` refers to the struct or enum variant's constructor.
+    Ctor(DefId, CtorOf, CtorKind),
     SelfCtor(DefId /* impl */),  // `DefId` refers to the impl
     Method(DefId),
     AssociatedConst(DefId),
@@ -265,10 +276,9 @@ impl Def {
     pub fn opt_def_id(&self) -> Option<DefId> {
         match *self {
             Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) |
-            Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) |
+            Def::Variant(id) | Def::Ctor(id, ..) | Def::Enum(id) |
             Def::TyAlias(id) | Def::TraitAlias(id) |
             Def::AssociatedTy(id) | Def::TyParam(id) | Def::ConstParam(id) | Def::Struct(id) |
-            Def::StructCtor(id, ..) |
             Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
             Def::AssociatedConst(id) | Def::Macro(id, ..) |
             Def::Existential(id) | Def::AssociatedExistential(id) | Def::ForeignTy(id) => {
@@ -303,20 +313,21 @@ impl Def {
             Def::Fn(..) => "function",
             Def::Mod(..) => "module",
             Def::Static(..) => "static",
-            Def::Variant(..) => "variant",
-            Def::VariantCtor(.., CtorKind::Fn) => "tuple variant",
-            Def::VariantCtor(.., CtorKind::Const) => "unit variant",
-            Def::VariantCtor(.., CtorKind::Fictive) => "struct variant",
             Def::Enum(..) => "enum",
+            Def::Variant(..) => "variant",
+            Def::Ctor(_, CtorOf::Variant, CtorKind::Fn) => "tuple variant",
+            Def::Ctor(_, CtorOf::Variant, CtorKind::Const) => "unit variant",
+            Def::Ctor(_, CtorOf::Variant, CtorKind::Fictive) => "struct variant",
+            Def::Struct(..) => "struct",
+            Def::Ctor(_, CtorOf::Struct, CtorKind::Fn) => "tuple struct",
+            Def::Ctor(_, CtorOf::Struct, CtorKind::Const) => "unit struct",
+            Def::Ctor(_, CtorOf::Struct, CtorKind::Fictive) =>
+                bug!("impossible struct constructor"),
             Def::Existential(..) => "existential type",
             Def::TyAlias(..) => "type alias",
             Def::TraitAlias(..) => "trait alias",
             Def::AssociatedTy(..) => "associated type",
             Def::AssociatedExistential(..) => "associated existential type",
-            Def::Struct(..) => "struct",
-            Def::StructCtor(.., CtorKind::Fn) => "tuple struct",
-            Def::StructCtor(.., CtorKind::Const) => "unit struct",
-            Def::StructCtor(.., CtorKind::Fictive) => bug!("impossible struct constructor"),
             Def::SelfCtor(..) => "self constructor",
             Def::Union(..) => "union",
             Def::Trait(..) => "trait",
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 977830315e2..bce528189ad 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -559,6 +559,7 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
                                         generics: &'v Generics,
                                         parent_item_id: HirId) {
     visitor.visit_ident(variant.node.ident);
+    visitor.visit_id(variant.node.id);
     visitor.visit_variant_data(&variant.node.data,
                                variant.node.ident.name,
                                generics,
@@ -923,7 +924,9 @@ pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'
 
 
 pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) {
-    visitor.visit_id(struct_definition.hir_id());
+    if let Some(ctor_hir_id) = struct_definition.ctor_hir_id() {
+        visitor.visit_id(ctor_hir_id);
+    }
     walk_list!(visitor, visit_struct_field, struct_definition.fields());
 }
 
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 2251e67233c..8db90035c8e 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1615,9 +1615,11 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_variant(&mut self, v: &Variant) -> hir::Variant {
+        let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(v.node.id);
         Spanned {
             node: hir::VariantKind {
                 ident: v.node.ident,
+                id: hir_id,
                 attrs: self.lower_attrs(&v.node.attrs),
                 data: self.lower_variant_data(&v.node.data),
                 disr_expr: v.node.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
@@ -2669,19 +2671,10 @@ impl<'a> LoweringContext<'a> {
 
     fn lower_variant_data(&mut self, vdata: &VariantData) -> hir::VariantData {
         match *vdata {
-            VariantData::Struct(ref fields, id, recovered) => {
-                let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id);
-
-                hir::VariantData::Struct(
-                    fields
-                        .iter()
-                        .enumerate()
-                        .map(|f| self.lower_struct_field(f))
-                        .collect(),
-                    hir_id,
-                    recovered,
-                )
-            },
+            VariantData::Struct(ref fields, recovered) => hir::VariantData::Struct(
+                fields.iter().enumerate().map(|f| self.lower_struct_field(f)).collect(),
+                recovered,
+            ),
             VariantData::Tuple(ref fields, id) => {
                 let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id);
 
@@ -2696,7 +2689,6 @@ impl<'a> LoweringContext<'a> {
             },
             VariantData::Unit(id) => {
                 let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id);
-
                 hir::VariantData::Unit(hir_id)
             },
         }
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index e88f9e60702..75d7d843dea 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -360,9 +360,9 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
             this.insert(i.span, i.hir_id, Node::Item(i));
             this.with_parent(i.hir_id, |this| {
                 if let ItemKind::Struct(ref struct_def, _) = i.node {
-                    // If this is a tuple-like struct, register the constructor.
-                    if !struct_def.is_struct() {
-                        this.insert(i.span, struct_def.hir_id(), Node::StructCtor(struct_def));
+                    // If this is a tuple or unit-like struct, register the constructor.
+                    if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
+                        this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
                     }
                 }
                 intravisit::walk_item(this, i);
@@ -515,8 +515,12 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_variant(&mut self, v: &'hir Variant, g: &'hir Generics, item_id: HirId) {
-        self.insert(v.span, v.node.data.hir_id(), Node::Variant(v));
-        self.with_parent(v.node.data.hir_id(), |this| {
+        self.insert(v.span, v.node.id, Node::Variant(v));
+        self.with_parent(v.node.id, |this| {
+            // Register the constructor of this variant.
+            if let Some(ctor_hir_id) = v.node.data.ctor_hir_id() {
+                this.insert(v.span, ctor_hir_id, Node::Ctor(&v.node.data));
+            }
             intravisit::walk_variant(this, v, g, item_id);
         });
     }
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 12760f8b982..1a3bbc5ecc4 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -158,12 +158,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
         self.with_parent(def, |this| {
             match i.node {
                 ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => {
-                    // If this is a tuple-like struct, register the constructor.
-                    if !struct_def.is_struct() {
-                        this.create_def(struct_def.id(),
-                                        DefPathData::StructCtor,
-                                        REGULAR_SPACE,
-                                        i.span);
+                    // If this is a unit or tuple-like struct, register the constructor.
+                    if let Some(ctor_hir_id) = struct_def.ctor_id() {
+                        this.create_def(ctor_hir_id, DefPathData::Ctor, REGULAR_SPACE, i.span);
                     }
                 }
                 _ => {}
@@ -193,11 +190,16 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
     }
 
     fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
-        let def = self.create_def(v.node.data.id(),
+        let def = self.create_def(v.node.id,
                                   DefPathData::EnumVariant(v.node.ident.as_interned_str()),
                                   REGULAR_SPACE,
                                   v.span);
-        self.with_parent(def, |this| visit::walk_variant(this, v, g, item_id));
+        self.with_parent(def, |this| {
+            if let Some(ctor_hir_id) = v.node.data.ctor_id() {
+                this.create_def(ctor_hir_id, DefPathData::Ctor, REGULAR_SPACE, v.span);
+            }
+            visit::walk_variant(this, v, g, item_id)
+        });
     }
 
     fn visit_variant_data(&mut self, data: &'a VariantData, _: Ident,
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index dca4ce4aef8..1006d813e65 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -366,8 +366,8 @@ pub enum DefPathData {
     EnumVariant(InternedString),
     /// A struct field
     Field(InternedString),
-    /// Implicit ctor for a tuple-like struct
-    StructCtor,
+    /// Implicit ctor for a unit or tuple-like struct or enum variant.
+    Ctor,
     /// A constant expression (see {ast,hir}::AnonConst).
     AnonConst,
     /// An `impl Trait` type node
@@ -652,7 +652,7 @@ impl DefPathData {
             CrateRoot |
             Misc |
             ClosureExpr |
-            StructCtor |
+            Ctor |
             AnonConst |
             ImplTrait => None
         }
@@ -683,7 +683,7 @@ impl DefPathData {
             Impl => "{{impl}}",
             Misc => "{{misc}}",
             ClosureExpr => "{{closure}}",
-            StructCtor => "{{constructor}}",
+            Ctor => "{{constructor}}",
             AnonConst => "{{constant}}",
             ImplTrait => "{{opaque}}",
         };
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 3e8da882eed..d810a9310c5 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -366,12 +366,18 @@ impl<'hir> Map<'hir> {
                 }
             }
             Node::Variant(variant) => {
-                let def_id = self.local_def_id_from_hir_id(variant.node.data.hir_id());
+                let def_id = self.local_def_id_from_hir_id(variant.node.id);
                 Some(Def::Variant(def_id))
             }
-            Node::StructCtor(variant) => {
-                let def_id = self.local_def_id_from_hir_id(variant.hir_id());
-                Some(Def::StructCtor(def_id, def::CtorKind::from_hir(variant)))
+            Node::Ctor(variant_data) => {
+                let ctor_of = match self.find(self.get_parent_node(node_id)) {
+                    Some(Node::Item(..)) => def::CtorOf::Struct,
+                    Some(Node::Variant(..)) => def::CtorOf::Variant,
+                    _ => unreachable!(),
+                };
+                variant_data.ctor_hir_id()
+                    .map(|hir_id| self.local_def_id_from_hir_id(hir_id))
+                    .map(|def_id| Def::Ctor(def_id, ctor_of, def::CtorKind::from_hir(variant_data)))
             }
             Node::AnonConst(_) |
             Node::Field(_) |
@@ -516,8 +522,7 @@ impl<'hir> Map<'hir> {
             Node::AnonConst(_) => {
                 BodyOwnerKind::Const
             }
-            Node::Variant(&Spanned { node: VariantKind { data: VariantData::Tuple(..), .. }, .. }) |
-            Node::StructCtor(..) |
+            Node::Ctor(..) |
             Node::Item(&Item { node: ItemKind::Fn(..), .. }) |
             Node::TraitItem(&TraitItem { node: TraitItemKind::Method(..), .. }) |
             Node::ImplItem(&ImplItem { node: ImplItemKind::Method(..), .. }) => {
@@ -948,8 +953,8 @@ impl<'hir> Map<'hir> {
                     _ => bug!("struct ID bound to non-struct {}", self.hir_to_string(id))
                 }
             }
-            Some(Node::StructCtor(data)) => data,
             Some(Node::Variant(variant)) => &variant.node.data,
+            Some(Node::Ctor(data)) => data,
             _ => bug!("expected struct or variant, found {}", self.hir_to_string(id))
         }
     }
@@ -993,7 +998,7 @@ impl<'hir> Map<'hir> {
             Node::Lifetime(lt) => lt.name.ident().name,
             Node::GenericParam(param) => param.name.ident().name,
             Node::Binding(&Pat { node: PatKind::Binding(_, _, l, _), .. }) => l.name,
-            Node::StructCtor(_) => self.name(self.get_parent(id)),
+            Node::Ctor(..) => self.name(self.get_parent(id)),
             _ => bug!("no name for {}", self.node_to_string(id))
         }
     }
@@ -1019,9 +1024,9 @@ impl<'hir> Map<'hir> {
             Some(Node::Expr(ref e)) => Some(&*e.attrs),
             Some(Node::Stmt(ref s)) => Some(s.node.attrs()),
             Some(Node::GenericParam(param)) => Some(&param.attrs[..]),
-            // unit/tuple structs take the attributes straight from
-            // the struct definition.
-            Some(Node::StructCtor(_)) => return self.attrs(self.get_parent(id)),
+            // Unit/tuple structs/variants take the attributes straight from
+            // the struct/variant definition.
+            Some(Node::Ctor(..)) => return self.attrs(self.get_parent(id)),
             _ => None
         };
         attrs.unwrap_or(&[])
@@ -1068,7 +1073,11 @@ impl<'hir> Map<'hir> {
             Some(Node::Binding(pat)) => pat.span,
             Some(Node::Pat(pat)) => pat.span,
             Some(Node::Block(block)) => block.span,
-            Some(Node::StructCtor(_)) => self.expect_item(self.get_parent(id)).span,
+            Some(Node::Ctor(..)) => match self.find(self.get_parent_node(id)) {
+                Some(Node::Item(item)) => item.span,
+                Some(Node::Variant(variant)) => variant.span,
+                _ => unreachable!(),
+            }
             Some(Node::Lifetime(lifetime)) => lifetime.span,
             Some(Node::GenericParam(param)) => param.span,
             Some(Node::Visibility(&Spanned {
@@ -1324,7 +1333,7 @@ impl<'a> print::State<'a> {
             // these cases do not carry enough information in the
             // hir_map to reconstruct their full structure for pretty
             // printing.
-            Node::StructCtor(_)   => bug!("cannot print isolated StructCtor"),
+            Node::Ctor(..)        => bug!("cannot print isolated Ctor"),
             Node::Local(a)        => self.print_local_decl(&a),
             Node::MacroDef(_)     => bug!("cannot print MacroDef"),
             Node::Crate           => bug!("cannot print Crate"),
@@ -1443,8 +1452,8 @@ fn node_id_to_string(map: &Map<'_>, id: NodeId, include_id: bool) -> String {
         Some(Node::Local(_)) => {
             format!("local {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(Node::StructCtor(_)) => {
-            format!("struct_ctor {}{}", path_str(), id_str)
+        Some(Node::Ctor(..)) => {
+            format!("ctor {}{}", path_str(), id_str)
         }
         Some(Node::Lifetime(_)) => {
             format!("lifetime {}{}", map.node_to_pretty_string(id), id_str)
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 823de08874e..1bf7eed71bf 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -2049,9 +2049,14 @@ pub struct EnumDef {
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub struct VariantKind {
+    /// Name of the variant.
     #[stable_hasher(project(name))]
     pub ident: Ident,
+    /// Attributes of the variant.
     pub attrs: HirVec<Attribute>,
+    /// Id of the variant (not the constructor, see `VariantData::ctor_hir_id()`).
+    pub id: HirId,
+    /// Fields and constructor id of the variant.
     pub data: VariantData,
     /// Explicit discriminant (e.g., `Foo = 1`).
     pub disr_expr: Option<AnonConst>,
@@ -2063,7 +2068,7 @@ pub type Variant = Spanned<VariantKind>;
 pub enum UseKind {
     /// One import, e.g., `use foo::bar` or `use foo::bar as baz`.
     /// Also produced for each element of a list `use`, e.g.
-    // `use foo::{a, b}` lowers to `use foo::a; use foo::b;`.
+    /// `use foo::{a, b}` lowers to `use foo::a; use foo::b;`.
     Single,
 
     /// Glob import, e.g., `use foo::*`.
@@ -2170,57 +2175,37 @@ impl StructField {
     }
 }
 
-/// Fields and Ids of enum variants and structs
-///
-/// For enum variants: `NodeId` represents both an Id of the variant itself (relevant for all
-/// variant kinds) and an Id of the variant's constructor (not relevant for `Struct`-variants).
-/// One shared Id can be successfully used for these two purposes.
-/// Id of the whole enum lives in `Item`.
-///
-/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually
-/// used for `Struct`-structs (but still present). Structures don't have an analogue of "Id of
-/// the variant itself" from enum variants.
-/// Id of the whole struct lives in `Item`.
+/// Fields and constructor ids of enum variants and structs
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum VariantData {
-    Struct(HirVec<StructField>, HirId, /* recovered */ bool),
+    /// Struct variant.
+    ///
+    /// e.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
+    Struct(HirVec<StructField>, /* recovered */ bool),
+    /// Tuple variant.
+    ///
+    /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
     Tuple(HirVec<StructField>, HirId),
+    /// Unit variant.
+    ///
+    /// E.g., `Bar = ..` as in `enum Foo { Bar = .. }`.
     Unit(HirId),
 }
 
 impl VariantData {
+    /// Return the fields of this variant.
     pub fn fields(&self) -> &[StructField] {
         match *self {
             VariantData::Struct(ref fields, ..) | VariantData::Tuple(ref fields, ..) => fields,
             _ => &[],
         }
     }
-    pub fn hir_id(&self) -> HirId {
+
+    /// Return the `HirId` of this variant's constructor, if it has one.
+    pub fn ctor_hir_id(&self) -> Option<HirId> {
         match *self {
-            VariantData::Struct(_, hir_id, _)
-            | VariantData::Tuple(_, hir_id)
-            | VariantData::Unit(hir_id) => hir_id,
-        }
-    }
-    pub fn is_struct(&self) -> bool {
-        if let VariantData::Struct(..) = *self {
-            true
-        } else {
-            false
-        }
-    }
-    pub fn is_tuple(&self) -> bool {
-        if let VariantData::Tuple(..) = *self {
-            true
-        } else {
-            false
-        }
-    }
-    pub fn is_unit(&self) -> bool {
-        if let VariantData::Unit(..) = *self {
-            true
-        } else {
-            false
+            VariantData::Struct(_, _) => None,
+            VariantData::Tuple(_, hir_id) | VariantData::Unit(hir_id) => Some(hir_id),
         }
     }
 }
@@ -2594,8 +2579,9 @@ pub enum Node<'hir> {
     Local(&'hir Local),
     MacroDef(&'hir MacroDef),
 
-    /// StructCtor represents a tuple struct.
-    StructCtor(&'hir VariantData),
+    /// `Ctor` refers to the constructor of an enum variant or struct. Only tuple or unit variants
+    /// with synthesized constructors.
+    Ctor(&'hir VariantData),
 
     Lifetime(&'hir Lifetime),
     GenericParam(&'hir GenericParam),
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index 18a3d6708db..e7eda5aab13 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -1,4 +1,4 @@
-use crate::hir::def::Def;
+use crate::hir::def::{CtorOf, Def};
 use crate::hir::def_id::DefId;
 use crate::hir::{self, HirId, PatKind};
 use syntax::ast;
@@ -55,7 +55,7 @@ impl hir::Pat {
             PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
             PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
                 match path.def {
-                    Def::Variant(..) | Def::VariantCtor(..) => true,
+                    Def::Variant(..) => true,
                     _ => false
                 }
             }
@@ -125,8 +125,8 @@ impl hir::Pat {
                 PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
                 PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
                     match path.def {
-                        Def::Variant(id) |
-                        Def::VariantCtor(id, ..) => variants.push(id),
+                        Def::Variant(id) => variants.push(id),
+                        Def::Ctor(id, CtorOf::Variant, ..) => variants.push(id),
                         _ => ()
                     }
                 }
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index bff4190ae79..cdd4043f4bc 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -860,41 +860,44 @@ impl<'a> State<'a> {
                         -> io::Result<()> {
         self.print_name(name)?;
         self.print_generic_params(&generics.params)?;
-        if !struct_def.is_struct() {
-            if struct_def.is_tuple() {
-                self.popen()?;
-                self.commasep(Inconsistent, struct_def.fields(), |s, field| {
-                    s.maybe_print_comment(field.span.lo())?;
-                    s.print_outer_attributes(&field.attrs)?;
-                    s.print_visibility(&field.vis)?;
-                    s.print_type(&field.ty)
-                })?;
-                self.pclose()?;
-            }
-            self.print_where_clause(&generics.where_clause)?;
-            if print_finalizer {
-                self.s.word(";")?;
+        match struct_def {
+            hir::VariantData::Tuple(..) | hir::VariantData::Unit(..) => {
+                if let hir::VariantData::Tuple(..) = struct_def {
+                    self.popen()?;
+                    self.commasep(Inconsistent, struct_def.fields(), |s, field| {
+                        s.maybe_print_comment(field.span.lo())?;
+                        s.print_outer_attributes(&field.attrs)?;
+                        s.print_visibility(&field.vis)?;
+                        s.print_type(&field.ty)
+                    })?;
+                    self.pclose()?;
+                }
+                self.print_where_clause(&generics.where_clause)?;
+                if print_finalizer {
+                    self.s.word(";")?;
+                }
+                self.end()?;
+                self.end() // close the outer-box
             }
-            self.end()?;
-            self.end() // close the outer-box
-        } else {
-            self.print_where_clause(&generics.where_clause)?;
-            self.nbsp()?;
-            self.bopen()?;
-            self.hardbreak_if_not_bol()?;
-
-            for field in struct_def.fields() {
+            hir::VariantData::Struct(..) => {
+                self.print_where_clause(&generics.where_clause)?;
+                self.nbsp()?;
+                self.bopen()?;
                 self.hardbreak_if_not_bol()?;
-                self.maybe_print_comment(field.span.lo())?;
-                self.print_outer_attributes(&field.attrs)?;
-                self.print_visibility(&field.vis)?;
-                self.print_ident(field.ident)?;
-                self.word_nbsp(":")?;
-                self.print_type(&field.ty)?;
-                self.s.word(",")?;
-            }
 
-            self.bclose(span)
+                for field in struct_def.fields() {
+                    self.hardbreak_if_not_bol()?;
+                    self.maybe_print_comment(field.span.lo())?;
+                    self.print_outer_attributes(&field.attrs)?;
+                    self.print_visibility(&field.vis)?;
+                    self.print_ident(field.ident)?;
+                    self.word_nbsp(":")?;
+                    self.print_type(&field.ty)?;
+                    self.s.word(",")?;
+                }
+
+                self.bclose(span)
+            }
         }
     }
 
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 9761ee31353..94f1d9c2710 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -917,7 +917,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
                      v: &'tcx hir::Variant,
                      g: &'tcx hir::Generics,
                      item_id: hir::HirId) {
-        self.with_lint_attrs(v.node.data.hir_id(), &v.node.attrs, |cx| {
+        self.with_lint_attrs(v.node.id, &v.node.attrs, |cx| {
             run_lints!(cx, check_variant, v, g);
             hir_visit::walk_variant(cx, v, g, item_id);
             run_lints!(cx, check_variant_post, v, g);
@@ -1073,7 +1073,9 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
                         item_id: ast::NodeId,
                         _: Span) {
         run_early_pass!(self, check_struct_def, s, ident, g, item_id);
-        self.check_id(s.id());
+        if let Some(ctor_hir_id) = s.ctor_id() {
+            self.check_id(ctor_hir_id);
+        }
         ast_visit::walk_struct_def(self, s);
         run_early_pass!(self, check_struct_def_post, s, ident, g, item_id);
     }
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index 03ed62f2a0d..e96fe3d3b77 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -803,7 +803,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'a, 'tcx> {
                      v: &'tcx hir::Variant,
                      g: &'tcx hir::Generics,
                      item_id: hir::HirId) {
-        self.with_lint_attrs(v.node.data.hir_id(), &v.node.attrs, |builder| {
+        self.with_lint_attrs(v.node.id, &v.node.attrs, |builder| {
             intravisit::walk_variant(builder, v, g, item_id);
         })
     }
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index ccec4bd1432..f12367a89bb 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -7,7 +7,7 @@ use crate::hir::{self, PatKind, TyKind};
 use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use crate::hir::itemlikevisit::ItemLikeVisitor;
 
-use crate::hir::def::Def;
+use crate::hir::def::{CtorOf, Def};
 use crate::hir::CodegenFnAttrFlags;
 use crate::hir::def_id::{DefId, LOCAL_CRATE};
 use crate::lint;
@@ -54,8 +54,7 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> {
 impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
     fn check_def_id(&mut self, def_id: DefId) {
         if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) {
-            if should_explore(self.tcx, hir_id) ||
-               self.struct_constructors.contains_key(&hir_id) {
+            if should_explore(self.tcx, hir_id) || self.struct_constructors.contains_key(&hir_id) {
                 self.worklist.push(hir_id);
             }
             self.live_symbols.insert(hir_id);
@@ -77,10 +76,17 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
             _ if self.in_pat => (),
             Def::PrimTy(..) | Def::SelfTy(..) | Def::SelfCtor(..) |
             Def::Local(..) | Def::Upvar(..) => {}
-            Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
-                if let Some(enum_id) = self.tcx.parent(variant_id) {
-                    self.check_def_id(enum_id);
+            Def::Ctor(ctor_def_id, CtorOf::Variant, ..) => {
+                let variant_id = self.tcx.parent(ctor_def_id).unwrap();
+                let enum_id = self.tcx.parent(variant_id).unwrap();
+                self.check_def_id(enum_id);
+                if !self.ignore_variant_stack.contains(&ctor_def_id) {
+                    self.check_def_id(variant_id);
                 }
+            }
+            Def::Variant(variant_id) => {
+                let enum_id = self.tcx.parent(variant_id).unwrap();
+                self.check_def_id(enum_id);
                 if !self.ignore_variant_stack.contains(&variant_id) {
                     self.check_def_id(variant_id);
                 }
@@ -360,9 +366,16 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
             self.worklist.push(item.hir_id);
         }
         match item.node {
-            hir::ItemKind::Enum(ref enum_def, _) if allow_dead_code => {
-                self.worklist.extend(enum_def.variants.iter()
-                                                      .map(|variant| variant.node.data.hir_id()));
+            hir::ItemKind::Enum(ref enum_def, _) => {
+                if allow_dead_code {
+                    self.worklist.extend(enum_def.variants.iter().map(|variant| variant.node.id));
+                }
+
+                for variant in &enum_def.variants {
+                    if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() {
+                        self.struct_constructors.insert(ctor_hir_id, variant.node.id);
+                    }
+                }
             }
             hir::ItemKind::Trait(.., ref trait_item_refs) => {
                 for trait_item_ref in trait_item_refs {
@@ -392,7 +405,9 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
                 }
             }
             hir::ItemKind::Struct(ref variant_data, _) => {
-                self.struct_constructors.insert(variant_data.hir_id(), item.hir_id);
+                if let Some(ctor_hir_id) = variant_data.ctor_hir_id() {
+                    self.struct_constructors.insert(ctor_hir_id, item.hir_id);
+                }
             }
             _ => ()
         }
@@ -484,9 +499,9 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
     }
 
     fn should_warn_about_variant(&mut self, variant: &hir::VariantKind) -> bool {
-        !self.symbol_is_live(variant.data.hir_id())
+        !self.symbol_is_live(variant.id)
             && !has_allow_dead_code_or_lang_attr(self.tcx,
-                                                 variant.data.hir_id(),
+                                                 variant.id,
                                                  &variant.attrs)
     }
 
@@ -583,7 +598,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
                      g: &'tcx hir::Generics,
                      id: hir::HirId) {
         if self.should_warn_about_variant(&variant.node) {
-            self.warn_dead_code(variant.node.data.hir_id(), variant.span, variant.node.ident.name,
+            self.warn_dead_code(variant.node.id, variant.span, variant.node.ident.name,
                                 "variant", "constructed");
         } else {
             intravisit::walk_variant(self, variant, g, id);
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 8ada67efaaf..6c8d9fe29d7 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -9,12 +9,12 @@ pub use self::MatchMode::*;
 use self::TrackMatchMode::*;
 use self::OverloadedCallType::*;
 
-use crate::hir::def::Def;
+use crate::hir::def::{CtorOf, Def};
 use crate::hir::def_id::DefId;
 use crate::infer::InferCtxt;
 use crate::middle::mem_categorization as mc;
 use crate::middle::region;
-use crate::ty::{self, TyCtxt, adjustment};
+use crate::ty::{self, DefIdTree, TyCtxt, adjustment};
 
 use crate::hir::{self, PatKind};
 use rustc_data_structures::sync::Lrc;
@@ -902,14 +902,20 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
             };
             let def = mc.tables.qpath_def(qpath, pat.hir_id);
             match def {
-                Def::Variant(variant_did) |
-                Def::VariantCtor(variant_did, ..) => {
+                Def::Ctor(variant_ctor_did, CtorOf::Variant, ..) => {
+                    let variant_did = mc.tcx.parent(variant_ctor_did).unwrap();
+                    let downcast_cmt = mc.cat_downcast_if_needed(pat, cmt_pat, variant_did);
+
+                    debug!("variantctor downcast_cmt={:?} pat={:?}", downcast_cmt, pat);
+                    delegate.matched_pat(pat, &downcast_cmt, match_mode);
+                }
+                Def::Variant(variant_did) => {
                     let downcast_cmt = mc.cat_downcast_if_needed(pat, cmt_pat, variant_did);
 
                     debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat);
                     delegate.matched_pat(pat, &downcast_cmt, match_mode);
                 }
-                Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
+                Def::Struct(..) | Def::Ctor(..) | Def::Union(..) |
                 Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => {
                     debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat);
                     delegate.matched_pat(pat, &cmt_pat, match_mode);
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index b36d2a57cb3..4b169dea06c 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -62,7 +62,7 @@ use crate::middle::region;
 use crate::hir::def_id::{DefId, LocalDefId};
 use crate::hir::Node;
 use crate::infer::InferCtxt;
-use crate::hir::def::{Def, CtorKind};
+use crate::hir::def::{CtorOf, Def, CtorKind};
 use crate::ty::adjustment;
 use crate::ty::{self, DefIdTree, Ty, TyCtxt};
 use crate::ty::fold::TypeFoldable;
@@ -704,7 +704,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                hir_id, expr_ty, def);
 
         match def {
-            Def::StructCtor(..) | Def::VariantCtor(..) | Def::Const(..) | Def::ConstParam(..) |
+            Def::Ctor(..) | Def::Const(..) | Def::ConstParam(..) |
             Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) | Def::SelfCtor(..) => {
                 Ok(self.cat_rvalue_node(hir_id, span, expr_ty))
             }
@@ -1274,12 +1274,14 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                         debug!("access to unresolvable pattern {:?}", pat);
                         return Err(())
                     }
-                    Def::VariantCtor(def_id, CtorKind::Fn) => {
-                        let enum_def = self.tcx.parent(def_id).unwrap();
-                        (self.cat_downcast_if_needed(pat, cmt, def_id),
-                        self.tcx.adt_def(enum_def).variant_with_id(def_id).fields.len())
+                    Def::Ctor(variant_ctor_did, CtorOf::Variant, CtorKind::Fn) => {
+                        let variant_did = self.tcx.parent(variant_ctor_did).unwrap();
+                        let enum_did = self.tcx.parent(variant_did).unwrap();
+                        (self.cat_downcast_if_needed(pat, cmt, variant_did),
+                         self.tcx.adt_def(enum_did)
+                             .variant_with_ctor_id(variant_ctor_did).fields.len())
                     }
-                    Def::StructCtor(_, CtorKind::Fn) | Def::SelfCtor(..) => {
+                    Def::Ctor(_, CtorOf::Struct, CtorKind::Fn) | Def::SelfCtor(..) => {
                         let ty = self.pat_ty_unadjusted(&pat)?;
                         match ty.sty {
                             ty::Adt(adt_def, _) => {
@@ -1314,8 +1316,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                         debug!("access to unresolvable pattern {:?}", pat);
                         return Err(())
                     }
-                    Def::Variant(variant_did) |
-                    Def::VariantCtor(variant_did, ..) => {
+                    Def::Ctor(variant_ctor_did, CtorOf::Variant, _) => {
+                        let variant_did = self.tcx.parent(variant_ctor_did).unwrap();
+                        self.cat_downcast_if_needed(pat, cmt, variant_did)
+                    }
+                    Def::Variant(variant_did) => {
                         self.cat_downcast_if_needed(pat, cmt, variant_did)
                     }
                     _ => cmt,
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index a7294dbf07c..b57f96f2d46 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -311,7 +311,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
             // Nothing to recurse on for these
             Node::ForeignItem(_) |
             Node::Variant(_) |
-            Node::StructCtor(_) |
+            Node::Ctor(..) |
             Node::Field(_) |
             Node::Ty(_) |
             Node::MacroDef(_) => {}
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 72c90b25860..772c6ab4745 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -258,8 +258,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
                 self.in_trait_impl = true;
             }
             hir::ItemKind::Struct(ref sd, _) => {
-                if !sd.is_struct() {
-                    self.annotate(sd.hir_id(), &i.attrs, i.span, AnnotationKind::Required, |_| {})
+                if let Some(ctor_hir_id) = sd.ctor_hir_id() {
+                    self.annotate(ctor_hir_id, &i.attrs, i.span, AnnotationKind::Required, |_| {})
                 }
             }
             _ => {}
@@ -289,8 +289,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     }
 
     fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: HirId) {
-        self.annotate(var.node.data.hir_id(), &var.node.attrs, var.span, AnnotationKind::Required,
-            |v| { intravisit::walk_variant(v, var, g, item_id) })
+        self.annotate(var.node.id, &var.node.attrs, var.span, AnnotationKind::Required,
+            |v| {
+                if let Some(ctor_hir_id) = var.node.data.ctor_hir_id() {
+                    v.annotate(ctor_hir_id, &var.node.attrs, var.span, AnnotationKind::Required,
+                               |_| {});
+                }
+
+                intravisit::walk_variant(v, var, g, item_id)
+            })
     }
 
     fn visit_struct_field(&mut self, s: &'tcx StructField) {
@@ -364,7 +371,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> {
     }
 
     fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: HirId) {
-        self.check_missing_stability(var.node.data.hir_id(), var.span, "variant");
+        self.check_missing_stability(var.node.id, var.span, "variant");
         intravisit::walk_variant(self, var, g, item_id);
     }
 
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 9f2027e7d05..d747f348ac9 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -2410,7 +2410,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                         ty::tls::with(|tcx| {
                             let substs = tcx.lift(&substs).expect("could not lift for printing");
                             FmtPrinter::new(tcx, f, Namespace::ValueNS)
-                                .print_def_path(variant_def.did, substs)?;
+                                .print_def_path(variant_def.def_id, substs)?;
                             Ok(())
                         })?;
 
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index f5f2ec38bdf..5b5a7cc9ed8 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -1077,23 +1077,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     _ => ArgKind::empty()
                 }).collect::<Vec<ArgKind>>())
             }
-            Node::Variant(&hir::Variant {
-                span,
-                node: hir::VariantKind {
-                    data: hir::VariantData::Tuple(ref fields, ..),
-                    ..
-                },
-                ..
-            }) => {
-                (self.tcx.sess.source_map().def_span(span),
-                 fields.iter().map(|field|
-                     ArgKind::Arg(field.ident.to_string(), "_".to_string())
-                 ).collect::<Vec<_>>())
-            }
-            Node::StructCtor(ref variant_data) => {
-                (self.tcx.sess.source_map().def_span(
-                    self.tcx.hir().span_by_hir_id(variant_data.hir_id())),
-                 vec![ArgKind::empty(); variant_data.fields().len()])
+            Node::Ctor(ref variant_data) => {
+                let span = variant_data.ctor_hir_id()
+                    .map(|hir_id| self.tcx.hir().span_by_hir_id(hir_id))
+                    .unwrap_or(DUMMY_SP);
+                let span = self.tcx.sess.source_map().def_span(span);
+
+                (span, vec![ArgKind::empty(); variant_data.fields().len()])
             }
             _ => panic!("non-FnLike node found: {:?}", node),
         }
diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs
index d732f3ff040..963b4b439f8 100644
--- a/src/librustc/ty/inhabitedness/mod.rs
+++ b/src/librustc/ty/inhabitedness/mod.rs
@@ -104,33 +104,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     fn ty_inhabitedness_forest(self, ty: Ty<'tcx>) -> DefIdForest {
         ty.uninhabited_from(self)
     }
-
-    pub fn is_enum_variant_uninhabited_from(self,
-                                            module: DefId,
-                                            variant: &'tcx VariantDef,
-                                            substs: SubstsRef<'tcx>)
-                                            -> bool
-    {
-        self.variant_inhabitedness_forest(variant, substs).contains(self, module)
-    }
-
-    pub fn is_variant_uninhabited_from_all_modules(self,
-                                                   variant: &'tcx VariantDef,
-                                                   substs: SubstsRef<'tcx>)
-                                                   -> bool
-    {
-        !self.variant_inhabitedness_forest(variant, substs).is_empty()
-    }
-
-    fn variant_inhabitedness_forest(self, variant: &'tcx VariantDef, substs: SubstsRef<'tcx>)
-                                    -> DefIdForest {
-        // Determine the ADT kind:
-        let adt_def_id = self.adt_def_id_of_variant(variant);
-        let adt_kind = self.adt_def(adt_def_id).adt_kind();
-
-        // Compute inhabitedness forest:
-        variant.uninhabited_from(self, substs, adt_kind)
-    }
 }
 
 impl<'a, 'gcx, 'tcx> AdtDef {
@@ -148,7 +121,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
 
 impl<'a, 'gcx, 'tcx> VariantDef {
     /// Calculate the forest of DefIds from which this variant is visibly uninhabited.
-    fn uninhabited_from(
+    pub fn uninhabited_from(
         &self,
         tcx: TyCtxt<'a, 'gcx, 'tcx>,
         substs: SubstsRef<'tcx>,
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index 995e85fc5f4..f54e69f352a 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -150,9 +150,7 @@ impl<'tcx> InstanceDef<'tcx> {
             _ => return true
         };
         match tcx.def_key(def_id).disambiguated_data.data {
-            DefPathData::StructCtor |
-            DefPathData::EnumVariant(..) |
-            DefPathData::ClosureExpr => true,
+            DefPathData::Ctor | DefPathData::ClosureExpr => true,
             _ => false
         }
     }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 91b84b68802..f0045136f41 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -6,9 +6,8 @@ pub use self::fold::TypeFoldable;
 
 use crate::hir::{map as hir_map, FreevarMap, GlobMap, TraitMap};
 use crate::hir::{HirId, Node};
-use crate::hir::def::{Def, CtorKind, ExportMap};
+use crate::hir::def::{Def, CtorOf, CtorKind, ExportMap};
 use crate::hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
-use crate::hir::map::DefPathData;
 use rustc_data_structures::svh::Svh;
 use rustc_macros::HashStable;
 use crate::ich::Fingerprint;
@@ -1775,12 +1774,19 @@ bitflags! {
     #[derive(HashStable)]
     pub struct AdtFlags: u32 {
         const NO_ADT_FLAGS        = 0;
+        /// Indicates whether the ADT is an enum.
         const IS_ENUM             = 1 << 0;
+        /// Indicates whether the ADT is a union.
         const IS_UNION            = 1 << 1;
+        /// Indicates whether the ADT is a struct.
         const IS_STRUCT           = 1 << 2;
+        /// Indicates whether the ADT is a struct and has a constructor.
         const HAS_CTOR            = 1 << 3;
+        /// Indicates whether the type is a `PhantomData`.
         const IS_PHANTOM_DATA     = 1 << 4;
+        /// Indicates whether the type has a `#[fundamental]` attribute.
         const IS_FUNDAMENTAL      = 1 << 5;
+        /// Indicates whether the type is a `Box`.
         const IS_BOX              = 1 << 6;
         /// Indicates whether the type is an `Arc`.
         const IS_ARC              = 1 << 7;
@@ -1801,55 +1807,73 @@ bitflags! {
     }
 }
 
+/// Definition of a variant -- a struct's fields or a enum variant.
 #[derive(Debug)]
 pub struct VariantDef {
-    /// The variant's `DefId`. If this is a tuple-like struct,
-    /// this is the `DefId` of the struct's ctor.
-    pub did: DefId,
-    pub ident: Ident, // struct's name if this is a struct
+    /// `DefId` that identifies the variant itself.
+    /// If this variant belongs to a struct or union, then this is a copy of its `DefId`.
+    pub def_id: DefId,
+    /// `DefId` that identifies the variant's constructor.
+    /// If this variant is a struct variant, then this is `None`.
+    pub ctor_def_id: Option<DefId>,
+    /// Variant or struct name.
+    pub ident: Ident,
+    /// Discriminant of this variant.
     pub discr: VariantDiscr,
+    /// Fields of this variant.
     pub fields: Vec<FieldDef>,
+    /// Type of constructor of variant.
     pub ctor_kind: CtorKind,
+    /// Flags of the variant (e.g. is field list non-exhaustive)?
     flags: VariantFlags,
+    /// Recovered?
     pub recovered: bool,
 }
 
 impl<'a, 'gcx, 'tcx> VariantDef {
     /// Creates a new `VariantDef`.
     ///
-    /// - `did` is the `DefId` used for the variant.
-    /// This is the constructor `DefId` for tuple stucts, and the variant `DefId` for everything
-    /// else.
-    /// - `attribute_def_id` is the DefId that has the variant's attributes.
-    /// This is the struct `DefId` for structs, and the variant `DefId` for variants.
+    /// `variant_did` is the `DefId` that identifies the enum variant (if this `VariantDef`
+    /// represents an enum variant).
+    ///
+    /// `ctor_did` is the `DefId` that identifies the constructor of unit or
+    /// tuple-variants/structs. If this is a `struct`-variant then this should be `None`.
     ///
-    /// Note that we *could* use the constructor `DefId`, because the constructor attributes
-    /// redirect to the base attributes, but compiling a small crate requires
-    /// loading the `AdtDef`s for all the structs in the universe (e.g., coherence for any
+    /// `parent_did` is the `DefId` of the `AdtDef` representing the enum or struct that
+    /// owns this variant. It is used for checking if a struct has `#[non_exhaustive]` w/out having
+    /// to go through the redirect of checking the ctor's attributes - but compiling a small crate
+    /// requires loading the `AdtDef`s for all the structs in the universe (e.g., coherence for any
     /// built-in trait), and we do not want to load attributes twice.
     ///
     /// If someone speeds up attribute loading to not be a performance concern, they can
     /// remove this hack and use the constructor `DefId` everywhere.
     pub fn new(
         tcx: TyCtxt<'a, 'gcx, 'tcx>,
-        did: DefId,
         ident: Ident,
+        variant_did: Option<DefId>,
+        ctor_def_id: Option<DefId>,
         discr: VariantDiscr,
         fields: Vec<FieldDef>,
-        adt_kind: AdtKind,
         ctor_kind: CtorKind,
-        attribute_def_id: DefId,
+        adt_kind: AdtKind,
+        parent_did: DefId,
         recovered: bool,
     ) -> Self {
-        debug!("VariantDef::new({:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?})", did, ident, discr,
-               fields, adt_kind, ctor_kind, attribute_def_id);
+        debug!(
+            "VariantDef::new(ident = {:?}, variant_did = {:?}, ctor_def_id = {:?}, discr = {:?},
+             fields = {:?}, ctor_kind = {:?}, adt_kind = {:?}, parent_did = {:?})",
+             ident, variant_did, ctor_def_id, discr, fields, ctor_kind, adt_kind, parent_did,
+        );
+
         let mut flags = VariantFlags::NO_VARIANT_FLAGS;
-        if adt_kind == AdtKind::Struct && tcx.has_attr(attribute_def_id, "non_exhaustive") {
-            debug!("found non-exhaustive field list for {:?}", did);
+        if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, "non_exhaustive") {
+            debug!("found non-exhaustive field list for {:?}", parent_did);
             flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
         }
+
         VariantDef {
-            did,
+            def_id: variant_did.unwrap_or(parent_did),
+            ctor_def_id,
             ident,
             discr,
             fields,
@@ -1859,6 +1883,7 @@ impl<'a, 'gcx, 'tcx> VariantDef {
         }
     }
 
+    /// Is this field list non-exhaustive?
     #[inline]
     pub fn is_field_list_non_exhaustive(&self) -> bool {
         self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE)
@@ -1866,7 +1891,8 @@ impl<'a, 'gcx, 'tcx> VariantDef {
 }
 
 impl_stable_hash_for!(struct VariantDef {
-    did,
+    def_id,
+    ctor_def_id,
     ident -> (ident.name),
     discr,
     fields,
@@ -1898,12 +1924,15 @@ pub struct FieldDef {
 
 /// The definition of an abstract data type -- a struct or enum.
 ///
-/// These are all interned (by `intern_adt_def`) into the `adt_defs`
-/// table.
+/// These are all interned (by `intern_adt_def`) into the `adt_defs` table.
 pub struct AdtDef {
+    /// `DefId` of the struct, enum or union item.
     pub did: DefId,
+    /// Variants of the ADT. If this is a struct or enum, then there will be a single variant.
     pub variants: IndexVec<self::layout::VariantIdx, VariantDef>,
+    /// Flags of the ADT (e.g. is this a struct? is this non-exhaustive?)
     flags: AdtFlags,
+    /// Repr options provided by the user.
     pub repr: ReprOptions,
 }
 
@@ -2102,11 +2131,14 @@ impl ReprOptions {
 }
 
 impl<'a, 'gcx, 'tcx> AdtDef {
-    fn new(tcx: TyCtxt<'_, '_, '_>,
-           did: DefId,
-           kind: AdtKind,
-           variants: IndexVec<VariantIdx, VariantDef>,
-           repr: ReprOptions) -> Self {
+    /// Creates a new `AdtDef`.
+    fn new(
+        tcx: TyCtxt<'_, '_, '_>,
+        did: DefId,
+        kind: AdtKind,
+        variants: IndexVec<VariantIdx, VariantDef>,
+        repr: ReprOptions
+    ) -> Self {
         debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
         let mut flags = AdtFlags::NO_ADT_FLAGS;
 
@@ -2120,13 +2152,8 @@ impl<'a, 'gcx, 'tcx> AdtDef {
             AdtKind::Struct => AdtFlags::IS_STRUCT,
         };
 
-        if let AdtKind::Struct = kind {
-            let variant_def = &variants[VariantIdx::new(0)];
-            let def_key = tcx.def_key(variant_def.did);
-            match def_key.disambiguated_data.data {
-                DefPathData::StructCtor => flags |= AdtFlags::HAS_CTOR,
-                _ => (),
-            }
+        if kind == AdtKind::Struct && variants[VariantIdx::new(0)].ctor_def_id.is_some() {
+            flags |= AdtFlags::HAS_CTOR;
         }
 
         let attrs = tcx.get_attrs(did);
@@ -2154,21 +2181,25 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         }
     }
 
+    /// Returns `true` if this is a struct.
     #[inline]
     pub fn is_struct(&self) -> bool {
         self.flags.contains(AdtFlags::IS_STRUCT)
     }
 
+    /// Returns `true` if this is a union.
     #[inline]
     pub fn is_union(&self) -> bool {
         self.flags.contains(AdtFlags::IS_UNION)
     }
 
+    /// Returns `true` if this is a enum.
     #[inline]
     pub fn is_enum(&self) -> bool {
         self.flags.contains(AdtFlags::IS_ENUM)
     }
 
+    /// Returns `true` if the variant list of this ADT is `#[non_exhaustive]`.
     #[inline]
     pub fn is_variant_list_non_exhaustive(&self) -> bool {
         self.flags.contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
@@ -2186,6 +2217,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         }
     }
 
+    /// Returns a description of this abstract data type.
     pub fn descr(&self) -> &'static str {
         match self.adt_kind() {
             AdtKind::Struct => "struct",
@@ -2194,6 +2226,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         }
     }
 
+    /// Returns a description of a variant of this abstract data type.
     #[inline]
     pub fn variant_descr(&self) -> &'static str {
         match self.adt_kind() {
@@ -2267,24 +2300,30 @@ impl<'a, 'gcx, 'tcx> AdtDef {
     }
 
     pub fn variant_with_id(&self, vid: DefId) -> &VariantDef {
-        self.variants
-            .iter()
-            .find(|v| v.did == vid)
+        self.variants.iter().find(|v| v.def_id == vid)
             .expect("variant_with_id: unknown variant")
     }
 
+    pub fn variant_with_ctor_id(&self, cid: DefId) -> &VariantDef {
+        self.variants.iter().find(|v| v.ctor_def_id == Some(cid))
+            .expect("variant_with_ctor_id: unknown variant")
+    }
+
     pub fn variant_index_with_id(&self, vid: DefId) -> VariantIdx {
-        self.variants
-            .iter_enumerated()
-            .find(|(_, v)| v.did == vid)
-            .expect("variant_index_with_id: unknown variant")
-            .0
+        self.variants.iter_enumerated().find(|(_, v)| v.def_id == vid)
+            .expect("variant_index_with_id: unknown variant").0
+    }
+
+    pub fn variant_index_with_ctor_id(&self, cid: DefId) -> VariantIdx {
+        self.variants.iter_enumerated().find(|(_, v)| v.ctor_def_id == Some(cid))
+            .expect("variant_index_with_ctor_id: unknown variant").0
     }
 
     pub fn variant_of_def(&self, def: Def) -> &VariantDef {
         match def {
-            Def::Variant(vid) | Def::VariantCtor(vid, ..) => self.variant_with_id(vid),
-            Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
+            Def::Variant(vid) => self.variant_with_id(vid),
+            Def::Ctor(cid, ..) => self.variant_with_ctor_id(cid),
+            Def::Struct(..) | Def::Union(..) |
             Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) |
             Def::SelfCtor(..) => self.non_enum_variant(),
             _ => bug!("unexpected def {:?} in variant_of_def", def)
@@ -2820,7 +2859,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<usize> {
         variant.fields.iter().position(|field| {
-            self.adjust_ident(ident, variant.did, hir::DUMMY_HIR_ID).0 == field.ident.modern()
+            self.adjust_ident(ident, variant.def_id, hir::DUMMY_HIR_ID).0 == field.ident.modern()
         })
     }
 
@@ -2895,50 +2934,41 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     // or variant or their constructors, panics otherwise.
     pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef {
         match def {
-            Def::Variant(did) | Def::VariantCtor(did, ..) => {
+            Def::Variant(did) => {
                 let enum_did = self.parent(did).unwrap();
                 self.adt_def(enum_did).variant_with_id(did)
             }
             Def::Struct(did) | Def::Union(did) => {
                 self.adt_def(did).non_enum_variant()
             }
-            Def::StructCtor(ctor_did, ..) => {
-                let did = self.parent(ctor_did).expect("struct ctor has no parent");
-                self.adt_def(did).non_enum_variant()
+            Def::Ctor(variant_ctor_did, CtorOf::Variant, ..) => {
+                let variant_did = self.parent(variant_ctor_did).unwrap();
+                let enum_did = self.parent(variant_did).unwrap();
+                self.adt_def(enum_did).variant_with_ctor_id(variant_ctor_did)
+            }
+            Def::Ctor(ctor_did, CtorOf::Struct, ..) => {
+                let struct_did = self.parent(ctor_did).expect("struct ctor has no parent");
+                self.adt_def(struct_did).non_enum_variant()
             }
             _ => bug!("expect_variant_def used with unexpected def {:?}", def)
         }
     }
 
-    /// Given a `VariantDef`, returns the def-id of the `AdtDef` of which it is a part.
-    pub fn adt_def_id_of_variant(self, variant_def: &'tcx VariantDef) -> DefId {
-        let def_key = self.def_key(variant_def.did);
-        match def_key.disambiguated_data.data {
-            // for enum variants and tuple structs, the def-id of the ADT itself
-            // is the *parent* of the variant
-            DefPathData::EnumVariant(..) | DefPathData::StructCtor =>
-                DefId { krate: variant_def.did.krate, index: def_key.parent.unwrap() },
-
-            // otherwise, for structs and unions, they share a def-id
-            _ => variant_def.did,
-        }
-    }
-
     pub fn item_name(self, id: DefId) -> InternedString {
         if id.index == CRATE_DEF_INDEX {
             self.original_crate_name(id.krate).as_interned_str()
         } else {
             let def_key = self.def_key(id);
-            // The name of a StructCtor is that of its struct parent.
-            if let hir_map::DefPathData::StructCtor = def_key.disambiguated_data.data {
-                self.item_name(DefId {
-                    krate: id.krate,
-                    index: def_key.parent.unwrap()
-                })
-            } else {
-                def_key.disambiguated_data.data.get_opt_name().unwrap_or_else(|| {
+            match def_key.disambiguated_data.data {
+                // The name of a constructor is that of its parent.
+                hir_map::DefPathData::Ctor =>
+                    self.item_name(DefId {
+                        krate: id.krate,
+                        index: def_key.parent.unwrap()
+                    }),
+                _ => def_key.disambiguated_data.data.get_opt_name().unwrap_or_else(|| {
                     bug!("item_name: no name for {:?}", self.def_path(id));
-                })
+                }),
             }
         }
     }
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 7701a10d8ee..c9a4961a8e0 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -285,14 +285,18 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
         let mut cur_def_key = self.tcx().def_key(def_id);
         debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);
 
-        // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
-        if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
-            let parent = DefId {
-                krate: def_id.krate,
-                index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
-            };
+        // For a constructor we want the name of its parent rather than <unnamed>.
+        match cur_def_key.disambiguated_data.data {
+            DefPathData::Ctor => {
+                let parent = DefId {
+                    krate: def_id.krate,
+                    index: cur_def_key.parent
+                        .expect("DefPathData::Ctor/VariantData missing a parent"),
+                };
 
-            cur_def_key = self.tcx().def_key(parent);
+                cur_def_key = self.tcx().def_key(parent);
+            },
+            _ => {},
         }
 
         let visible_parent = match visible_parent_map.get(&def_id).cloned() {
@@ -860,7 +864,7 @@ impl TyCtxt<'_, '_, '_> {
             DefPathData::AnonConst |
             DefPathData::ConstParam(..) |
             DefPathData::ClosureExpr |
-            DefPathData::StructCtor => Namespace::ValueNS,
+            DefPathData::Ctor => Namespace::ValueNS,
 
             DefPathData::MacroDef(..) => Namespace::MacroNS,
 
@@ -1024,7 +1028,7 @@ impl<F: fmt::Write> Printer<'gcx, 'tcx> for FmtPrinter<'_, 'gcx, 'tcx, F> {
 
         // Skip `::{{constructor}}` on tuple/unit structs.
         match disambiguated_data.data {
-            DefPathData::StructCtor => return Ok(self),
+            DefPathData::Ctor => return Ok(self),
             _ => {}
         }
 
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 4fb2bfb075c..ccead14e76b 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -549,8 +549,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     /// Returns `true` if this `DefId` refers to the implicit constructor for
     /// a tuple struct like `struct Foo(u32)`, and `false` otherwise.
-    pub fn is_struct_constructor(self, def_id: DefId) -> bool {
-        self.def_key(def_id).disambiguated_data.data == DefPathData::StructCtor
+    pub fn is_constructor(self, def_id: DefId) -> bool {
+        self.def_key(def_id).disambiguated_data.data == DefPathData::Ctor
     }
 
     /// Given the `DefId` of a fn or closure, returns the `DefId` of
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 4e1d360562d..09de907b751 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -85,8 +85,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId)
     let owner_id = tcx.hir().as_local_hir_id(owner_def_id).unwrap();
 
     match tcx.hir().get_by_hir_id(owner_id) {
-        Node::StructCtor(_) |
-        Node::Variant(_) => {
+        Node::Ctor(..) => {
             // We get invoked with anything that has MIR, but some of
             // those things (notably the synthesized constructors from
             // tuple structs/variants) do not have an associated body
diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
index 0fa935199f9..ebd48f0ae1e 100644
--- a/src/librustc_codegen_utils/symbol_names.rs
+++ b/src/librustc_codegen_utils/symbol_names.rs
@@ -522,7 +522,7 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
 
         // Skip `::{{constructor}}` on tuple/unit structs.
         match disambiguated_data.data {
-            DefPathData::StructCtor => return Ok(self),
+            DefPathData::Ctor => return Ok(self),
             _ => {}
         }
 
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 8153653e48b..6d694dcfac7 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -528,7 +528,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
 
     fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant, _: &hir::Generics) {
         self.check_missing_docs_attrs(cx,
-                                      Some(v.node.data.hir_id()),
+                                      Some(v.node.id),
                                       &v.node.attrs,
                                       v.span,
                                       "a variant");
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 67a249e605e..995532a00cd 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -407,6 +407,14 @@ impl cstore::CStore {
         self.get_crate_data(def.krate).get_struct_field_names(def.index)
     }
 
+    pub fn ctor_kind_untracked(&self, def: DefId) -> def::CtorKind {
+        self.get_crate_data(def.krate).get_ctor_kind(def.index)
+    }
+
+    pub fn item_attrs_untracked(&self, def: DefId, sess: &Session) -> Lrc<[ast::Attribute]> {
+        self.get_crate_data(def.krate).get_item_attrs(def.index, sess)
+    }
+
     pub fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec<def::Export> {
         let mut result = vec![];
         self.get_crate_data(def_id.krate)
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index c608c03095a..fb519407398 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -8,7 +8,7 @@ use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash, Definitions};
 use rustc::hir;
 use rustc::middle::cstore::LinkagePreference;
 use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
-use rustc::hir::def::{self, Def, CtorKind};
+use rustc::hir::def::{self, Def, CtorOf, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, DefIndexAddressSpace,
                          CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId};
 use rustc::hir::map::definitions::DefPathTable;
@@ -544,13 +544,14 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    fn get_variant(&self,
-                   tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                   item: &Entry<'_>,
-                   index: DefIndex,
-                   adt_kind: ty::AdtKind)
-                   -> ty::VariantDef
-    {
+    fn get_variant(
+        &self,
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        item: &Entry<'_>,
+        index: DefIndex,
+        parent_did: DefId,
+        adt_kind: ty::AdtKind
+    ) -> ty::VariantDef {
         let data = match item.kind {
             EntryKind::Variant(data) |
             EntryKind::Struct(data, _) |
@@ -558,13 +559,18 @@ impl<'a, 'tcx> CrateMetadata {
             _ => bug!(),
         };
 
-        let def_id = self.local_def_id(data.struct_ctor.unwrap_or(index));
-        let attribute_def_id = self.local_def_id(index);
+        let variant_did = if adt_kind == ty::AdtKind::Enum {
+            Some(self.local_def_id(index))
+        } else {
+            None
+        };
+        let ctor_did = data.ctor.map(|index| self.local_def_id(index));
 
         ty::VariantDef::new(
             tcx,
-            def_id,
             Ident::from_interned_str(self.item_name(index)),
+            variant_did,
+            ctor_did,
             data.discr,
             item.children.decode(self).map(|index| {
                 let f = self.entry(index);
@@ -574,9 +580,9 @@ impl<'a, 'tcx> CrateMetadata {
                     vis: f.visibility.decode(self)
                 }
             }).collect(),
-            adt_kind,
             data.ctor_kind,
-            attribute_def_id,
+            adt_kind,
+            parent_did,
             false,
         )
     }
@@ -599,11 +605,11 @@ impl<'a, 'tcx> CrateMetadata {
             item.children
                 .decode(self)
                 .map(|index| {
-                    self.get_variant(tcx, &self.entry(index), index, kind)
+                    self.get_variant(tcx, &self.entry(index), index, did, kind)
                 })
                 .collect()
         } else {
-            std::iter::once(self.get_variant(tcx, &item, item_id, kind)).collect()
+            std::iter::once(self.get_variant(tcx, &item, item_id, did, kind)).collect()
         };
 
         tcx.alloc_adt_def(did, kind, variants, repr)
@@ -808,22 +814,22 @@ impl<'a, 'tcx> CrateMetadata {
                     // Re-export lists automatically contain constructors when necessary.
                     match def {
                         Def::Struct(..) => {
-                            if let Some(ctor_def_id) = self.get_struct_ctor_def_id(child_index) {
+                            if let Some(ctor_def_id) = self.get_ctor_def_id(child_index) {
                                 let ctor_kind = self.get_ctor_kind(child_index);
-                                let ctor_def = Def::StructCtor(ctor_def_id, ctor_kind);
-                                callback(def::Export {
-                                    def: ctor_def,
-                                    vis: self.get_visibility(ctor_def_id.index),
-                                    ident, span,
-                                });
+                                let ctor_def = Def::Ctor(ctor_def_id, CtorOf::Struct, ctor_kind);
+                                let vis = self.get_visibility(ctor_def_id.index);
+                                callback(def::Export { def: ctor_def, vis, ident, span });
                             }
                         }
                         Def::Variant(def_id) => {
                             // Braced variants, unlike structs, generate unusable names in
                             // value namespace, they are reserved for possible future use.
+                            // It's ok to use the variant's id as a ctor id since an
+                            // error will be reported on any use of such resolution anyway.
+                            let ctor_def_id = self.get_ctor_def_id(child_index).unwrap_or(def_id);
                             let ctor_kind = self.get_ctor_kind(child_index);
-                            let ctor_def = Def::VariantCtor(def_id, ctor_kind);
-                            let vis = self.get_visibility(child_index);
+                            let ctor_def = Def::Ctor(ctor_def_id, CtorOf::Variant, ctor_kind);
+                            let vis = self.get_visibility(ctor_def_id.index);
                             callback(def::Export { def: ctor_def, ident, vis, span });
                         }
                         _ => {}
@@ -925,10 +931,13 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
+    pub fn get_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
         match self.entry(node_id).kind {
             EntryKind::Struct(data, _) => {
-                data.decode(self).struct_ctor.map(|index| self.local_def_id(index))
+                data.decode(self).ctor.map(|index| self.local_def_id(index))
+            }
+            EntryKind::Variant(data) => {
+                data.decode(self).ctor.map(|index| self.local_def_id(index))
             }
             _ => None,
         }
@@ -939,11 +948,11 @@ impl<'a, 'tcx> CrateMetadata {
             return Lrc::new([]);
         }
 
-        // The attributes for a tuple struct are attached to the definition, not the ctor;
+        // The attributes for a tuple struct/variant are attached to the definition, not the ctor;
         // we assume that someone passing in a tuple struct ctor is actually wanting to
         // look at the definition
         let def_key = self.def_key(node_id);
-        let item_id = if def_key.disambiguated_data.data == DefPathData::StructCtor {
+        let item_id = if def_key.disambiguated_data.data == DefPathData::Ctor {
             def_key.parent.unwrap()
         } else {
             node_id
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index ce0618d4599..78a186fbb71 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -572,24 +572,21 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
     /// will have to lookup the adt-def by its id, and that gives us
     /// the right to access any information in the adt-def (including,
     /// e.g., the length of the various vectors).
-    fn encode_enum_variant_info(&mut self,
-                                (enum_did, Untracked(index)): (DefId, Untracked<VariantIdx>))
-                                -> Entry<'tcx> {
+    fn encode_enum_variant_info(
+        &mut self,
+        (enum_did, Untracked(index)): (DefId, Untracked<VariantIdx>),
+    ) -> Entry<'tcx> {
         let tcx = self.tcx;
         let def = tcx.adt_def(enum_did);
         let variant = &def.variants[index];
-        let def_id = variant.did;
+        let def_id = variant.def_id;
         debug!("IsolatedEncoder::encode_enum_variant_info({:?})", def_id);
 
         let data = VariantData {
             ctor_kind: variant.ctor_kind,
             discr: variant.discr,
-            struct_ctor: None,
-            ctor_sig: if variant.ctor_kind == CtorKind::Fn {
-                Some(self.lazy(&tcx.fn_sig(def_id)))
-            } else {
-                None
-            }
+            ctor: variant.ctor_def_id.map(|did| did.index),
+            ctor_sig: None,
         };
 
         let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap();
@@ -622,6 +619,57 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
         }
     }
 
+    /// Encode the constructor for the given variant of the given ADT. See
+    /// `encode_enum_variant_info` for an explanation about why the index is untracked.
+    fn encode_enum_variant_ctor(
+        &mut self,
+        (enum_did, Untracked(index)): (DefId, Untracked<VariantIdx>),
+    ) -> Entry<'tcx> {
+        let tcx = self.tcx;
+        let def = tcx.adt_def(enum_did);
+        let variant = &def.variants[index];
+        let def_id = variant.ctor_def_id.unwrap();
+        debug!("IsolatedEncoder::encode_enum_variant_ctor({:?})", def_id);
+
+        let data = VariantData {
+            ctor_kind: variant.ctor_kind,
+            discr: variant.discr,
+            ctor: Some(def_id.index),
+            ctor_sig: if variant.ctor_kind == CtorKind::Fn {
+                Some(self.lazy(&tcx.fn_sig(def_id)))
+            } else {
+                None
+            }
+        };
+
+        // Variant constructors have the same visibility as the parent enums.
+        let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap();
+        let enum_vis = &tcx.hir().expect_item_by_hir_id(enum_id).vis;
+
+        Entry {
+            kind: EntryKind::Variant(self.lazy(&data)),
+            visibility: self.lazy(&ty::Visibility::from_hir(enum_vis, enum_id, tcx)),
+            span: self.lazy(&tcx.def_span(def_id)),
+            attributes: LazySeq::empty(),
+            children: LazySeq::empty(),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: Some(self.encode_item_type(def_id)),
+            inherent_impls: LazySeq::empty(),
+            variances: if variant.ctor_kind == CtorKind::Fn {
+                self.encode_variances_of(def_id)
+            } else {
+                LazySeq::empty()
+            },
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+            predicates_defined_on: None,
+
+            mir: self.encode_optimized_mir(def_id),
+        }
+    }
+
     fn encode_info_for_mod(&mut self,
                            FromId(id, (md, attrs, vis)): FromId<(&hir::Mod,
                                                                  &[ast::Attribute],
@@ -678,7 +726,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
         let def_id = field.did;
         debug!("IsolatedEncoder::encode_field({:?})", def_id);
 
-        let variant_id = tcx.hir().as_local_hir_id(variant.did).unwrap();
+        let variant_id = tcx.hir().as_local_hir_id(variant.def_id).unwrap();
         let variant_data = tcx.hir().expect_variant_data(variant_id);
 
         Entry {
@@ -710,7 +758,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
         let data = VariantData {
             ctor_kind: variant.ctor_kind,
             discr: variant.discr,
-            struct_ctor: Some(def_id.index),
+            ctor: Some(def_id.index),
             ctor_sig: if variant.ctor_kind == CtorKind::Fn {
                 Some(self.lazy(&tcx.fn_sig(def_id)))
             } else {
@@ -1072,18 +1120,15 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
                 // Encode def_ids for each field and method
                 // for methods, write all the stuff get_trait_method
                 // needs to know
-                let struct_ctor = if !struct_def.is_struct() {
-                    Some(tcx.hir().local_def_id_from_hir_id(struct_def.hir_id()).index)
-                } else {
-                    None
-                };
+                let ctor = struct_def.ctor_hir_id()
+                    .map(|ctor_hir_id| tcx.hir().local_def_id_from_hir_id(ctor_hir_id).index);
 
                 let repr_options = get_repr_options(&tcx, def_id);
 
                 EntryKind::Struct(self.lazy(&VariantData {
                     ctor_kind: variant.ctor_kind,
                     discr: variant.discr,
-                    struct_ctor,
+                    ctor,
                     ctor_sig: None,
                 }), repr_options)
             }
@@ -1094,7 +1139,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
                 EntryKind::Union(self.lazy(&VariantData {
                     ctor_kind: variant.ctor_kind,
                     discr: variant.discr,
-                    struct_ctor: None,
+                    ctor: None,
                     ctor_sig: None,
                 }), repr_options)
             }
@@ -1171,8 +1216,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
                 hir::ItemKind::Enum(..) => {
                     let def = self.tcx.adt_def(def_id);
                     self.lazy_seq(def.variants.iter().map(|v| {
-                        assert!(v.did.is_local());
-                        v.did.index
+                        assert!(v.def_id.is_local());
+                        v.def_id.index
                     }))
                 }
                 hir::ItemKind::Struct(..) |
@@ -1765,17 +1810,23 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
 
                 let def = self.tcx.adt_def(def_id);
                 for (i, variant) in def.variants.iter_enumerated() {
-                    self.record(variant.did,
+                    self.record(variant.def_id,
                                 IsolatedEncoder::encode_enum_variant_info,
                                 (def_id, Untracked(i)));
+
+                    if let Some(ctor_def_id) = variant.ctor_def_id {
+                        self.record(ctor_def_id,
+                                    IsolatedEncoder::encode_enum_variant_ctor,
+                                    (def_id, Untracked(i)));
+                    }
                 }
             }
             hir::ItemKind::Struct(ref struct_def, _) => {
                 self.encode_fields(def_id);
 
                 // If the struct has a constructor, encode it.
-                if !struct_def.is_struct() {
-                    let ctor_def_id = self.tcx.hir().local_def_id_from_hir_id(struct_def.hir_id());
+                if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
+                    let ctor_def_id = self.tcx.hir().local_def_id_from_hir_id(ctor_hir_id);
                     self.record(ctor_def_id,
                                 IsolatedEncoder::encode_struct_ctor,
                                 (def_id, ctor_def_id));
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index afeea9947b5..5b6166ebeaf 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -445,11 +445,8 @@ impl_stable_hash_for!(struct FnData<'tcx> { constness, arg_names, sig });
 pub struct VariantData<'tcx> {
     pub ctor_kind: CtorKind,
     pub discr: ty::VariantDiscr,
-
-    /// If this is a struct's only variant, this
-    /// is the index of the "struct ctor" item.
-    pub struct_ctor: Option<DefIndex>,
-
+    /// If this is unit or tuple-variant/struct, then this is the index of the ctor id.
+    pub ctor: Option<DefIndex>,
     /// If this is a tuple struct or variant
     /// ctor, this is its "function" signature.
     pub ctor_sig: Option<Lazy<ty::PolyFnSig<'tcx>>>,
@@ -458,7 +455,7 @@ pub struct VariantData<'tcx> {
 impl_stable_hash_for!(struct VariantData<'tcx> {
     ctor_kind,
     discr,
-    struct_ctor,
+    ctor,
     ctor_sig
 });
 
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 551f18b95fe..dc37c1a67c0 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -75,8 +75,8 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> BorrowC
     // Return early if we are not supposed to use MIR borrow checker for this function.
     return_early = !tcx.has_attr(def_id, "rustc_mir") && !tcx.use_mir_borrowck();
 
-    if tcx.is_struct_constructor(def_id) {
-        // We are not borrow checking the automatically generated struct constructors
+    if tcx.is_constructor(def_id) {
+        // We are not borrow checking the automatically generated struct/variant constructors
         // because we want to accept structs such as this (taken from the `linked-hash-map`
         // crate):
         // ```rust
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 25a3160a498..d3d6b986277 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -2685,8 +2685,8 @@ impl MirPass for TypeckMir {
             return;
         }
 
-        if tcx.is_struct_constructor(def_id) {
-            // We just assume that the automatically generated struct constructors are
+        if tcx.is_constructor(def_id) {
+            // We just assume that the automatically generated struct/variant constructors are
             // correct. See the comment in the `mir_borrowck` implementation for an
             // explanation why we need this.
             return;
diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs
index 77978d7d38f..2e4f53023f4 100644
--- a/src/librustc_mir/build/matches/simplify.rs
+++ b/src/librustc_mir/build/matches/simplify.rs
@@ -163,7 +163,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     i == variant_index || {
                         self.hir.tcx().features().never_type &&
                         self.hir.tcx().features().exhaustive_patterns &&
-                        self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs)
+                        !v.uninhabited_from(self.hir.tcx(), substs, adt_def.adt_kind()).is_empty()
                     }
                 });
                 if irrefutable {
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 1138edcb375..7fe86d11c9e 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -31,10 +31,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
 
     // Figure out what primary body this item has.
     let (body_id, return_ty_span) = match tcx.hir().get_by_hir_id(id) {
-        Node::Variant(variant) =>
-            return create_constructor_shim(tcx, id, &variant.node.data),
-        Node::StructCtor(ctor) =>
-            return create_constructor_shim(tcx, id, ctor),
+        Node::Ctor(ctor) => return create_constructor_shim(tcx, id, ctor),
 
         Node::Expr(hir::Expr { node: hir::ExprKind::Closure(_, decl, body_id, _, _), .. })
         | Node::Item(hir::Item { node: hir::ItemKind::Fn(decl, _, _, body_id), .. })
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index b83f048114b..2ca44ecaba2 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -4,7 +4,7 @@ use crate::hair::cx::block;
 use crate::hair::cx::to_ref::ToRef;
 use crate::hair::util::UserAnnotatedTyHelpers;
 use rustc_data_structures::indexed_vec::Idx;
-use rustc::hir::def::{Def, CtorKind};
+use rustc::hir::def::{CtorOf, Def, CtorKind};
 use rustc::mir::interpret::{GlobalId, ErrorHandled, ConstValue};
 use rustc::ty::{self, AdtKind, Ty};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
@@ -261,10 +261,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     // Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
                     expr_ty.ty_adt_def().and_then(|adt_def| {
                         match path.def {
-                            Def::VariantCtor(variant_id, CtorKind::Fn) => {
-                                Some((adt_def, adt_def.variant_index_with_id(variant_id)))
-                            }
-                            Def::StructCtor(_, CtorKind::Fn) |
+                            Def::Ctor(ctor_id, _, CtorKind::Fn) =>
+                                Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id))),
                             Def::SelfCtor(..) => Some((adt_def, VariantIdx::new(0))),
                             _ => None,
                         }
@@ -677,8 +675,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         .ty_adt_def()
                         .and_then(|adt_def| {
                         match def {
-                            Def::VariantCtor(variant_id, CtorKind::Const) => {
-                                let idx = adt_def.variant_index_with_id(variant_id);
+                            Def::Ctor(variant_ctor_id, CtorOf::Variant, CtorKind::Const) => {
+                                let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id);
                                 let (d, o) = adt_def.discriminant_def_for_variant(idx);
                                 use rustc::ty::util::IntTypeExt;
                                 let ty = adt_def.repr.discr_type();
@@ -804,8 +802,7 @@ fn user_substs_applied_to_def(
         // `Fn` but with the user-given substitutions.
         Def::Fn(_) |
         Def::Method(_) |
-        Def::StructCtor(_, CtorKind::Fn) |
-        Def::VariantCtor(_, CtorKind::Fn) |
+        Def::Ctor(_, _, CtorKind::Fn) |
         Def::Const(_) |
         Def::AssociatedConst(_) => cx.tables().user_provided_types().get(hir_id).map(|u_ty| *u_ty),
 
@@ -813,8 +810,7 @@ fn user_substs_applied_to_def(
         // `None`). This has the type of the enum/struct that defines
         // this variant -- but with the substitutions given by the
         // user.
-        Def::StructCtor(_def_id, CtorKind::Const) |
-        Def::VariantCtor(_def_id, CtorKind::Const) =>
+        Def::Ctor(_, _, CtorKind::Const) =>
             cx.user_substs_applied_to_ty_of_hir_id(hir_id),
 
         // `Self` is used in expression as a tuple struct constructor or an unit struct constructor
@@ -911,8 +907,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         // A regular function, constructor function or a constant.
         Def::Fn(_) |
         Def::Method(_) |
-        Def::StructCtor(_, CtorKind::Fn) |
-        Def::VariantCtor(_, CtorKind::Fn) |
+        Def::Ctor(_, _, CtorKind::Fn) |
         Def::SelfCtor(..) => {
             let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def);
             debug!("convert_path_expr: user_ty={:?}", user_ty);
@@ -956,8 +951,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             }
         },
 
-        Def::StructCtor(def_id, CtorKind::Const) |
-        Def::VariantCtor(def_id, CtorKind::Const) => {
+        Def::Ctor(def_id, _, CtorKind::Const) => {
             let user_provided_types = cx.tables.user_provided_types();
             let user_provided_type = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty);
             debug!("convert_path_expr: user_provided_type={:?}", user_provided_type);
@@ -968,7 +962,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 ty::Adt(adt_def, substs) => {
                     ExprKind::Adt {
                         adt_def,
-                        variant_index: adt_def.variant_index_with_id(def_id),
+                        variant_index: adt_def.variant_index_with_ctor_id(def_id),
                         substs,
                         user_ty: user_provided_type,
                         fields: vec![],
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 88d1eb2ee0b..303ffcb3bfb 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -168,7 +168,7 @@ use super::{PatternFoldable, PatternFolder, compare_const_vals};
 
 use rustc::hir::def_id::DefId;
 use rustc::hir::RangeEnd;
-use rustc::ty::{self, subst::SubstsRef, Ty, TyCtxt, TypeFoldable, Const};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const};
 use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size};
 
 use rustc::mir::Field;
@@ -399,22 +399,10 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
             _ => false,
         }
     }
-
-    fn is_variant_uninhabited(&self,
-                              variant: &'tcx ty::VariantDef,
-                              substs: SubstsRef<'tcx>)
-                              -> bool
-    {
-        if self.tcx.features().exhaustive_patterns {
-            self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs)
-        } else {
-            false
-        }
-    }
 }
 
 #[derive(Clone, Debug, PartialEq)]
-pub enum Constructor<'tcx> {
+enum Constructor<'tcx> {
     /// The constructor of all patterns that don't vary by constructor,
     /// e.g., struct patterns and fixed-length arrays.
     Single,
@@ -435,7 +423,7 @@ impl<'tcx> Constructor<'tcx> {
         adt: &'tcx ty::AdtDef,
     ) -> VariantIdx {
         match self {
-            &Variant(vid) => adt.variant_index_with_id(vid),
+            &Variant(id) => adt.variant_index_with_id(id),
             &Single => {
                 assert!(!adt.is_enum());
                 VariantIdx::new(0)
@@ -658,8 +646,11 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
         }
         ty::Adt(def, substs) if def.is_enum() => {
             def.variants.iter()
-                .filter(|v| !cx.is_variant_uninhabited(v, substs))
-                .map(|v| Variant(v.did))
+                .filter(|v| {
+                    !cx.tcx.features().exhaustive_patterns ||
+                    !v.uninhabited_from(cx.tcx, substs, def.adt_kind()).contains(cx.tcx, cx.module)
+                })
+                .map(|v| Variant(v.def_id))
                 .collect()
         }
         ty::Char => {
@@ -1307,7 +1298,7 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
         PatternKind::Binding { .. } | PatternKind::Wild => None,
         PatternKind::Leaf { .. } | PatternKind::Deref { .. } => Some(vec![Single]),
         PatternKind::Variant { adt_def, variant_index, .. } => {
-            Some(vec![Variant(adt_def.variants[variant_index].did)])
+            Some(vec![Variant(adt_def.variants[variant_index].def_id)])
         }
         PatternKind::Constant { value } => Some(vec![ConstantValue(value)]),
         PatternKind::Range(PatternRange { lo, hi, ty, end }) =>
@@ -1742,11 +1733,9 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
 
         PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
             let ref variant = adt_def.variants[variant_index];
-            if *constructor == Variant(variant.did) {
-                Some(patterns_for_variant(subpatterns, wild_patterns))
-            } else {
-                None
-            }
+            Some(Variant(variant.def_id))
+                .filter(|variant_constructor| variant_constructor == constructor)
+                .map(|_| patterns_for_variant(subpatterns, wild_patterns))
         }
 
         PatternKind::Leaf { ref subpatterns } => {
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 8614be8d407..6c532fce57f 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -18,7 +18,7 @@ use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTyp
 use rustc::ty::subst::{SubstsRef, Kind};
 use rustc::ty::layout::VariantIdx;
 use rustc::hir::{self, PatKind, RangeEnd};
-use rustc::hir::def::{Def, CtorKind};
+use rustc::hir::def::{CtorOf, Def, CtorKind};
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 
 use rustc_data_structures::indexed_vec::Idx;
@@ -733,8 +733,16 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
         ty: Ty<'tcx>,
         subpatterns: Vec<FieldPattern<'tcx>>,
     ) -> PatternKind<'tcx> {
+        let def = match def {
+            Def::Ctor(variant_ctor_id, CtorOf::Variant, ..) => {
+                let variant_id = self.tcx.parent(variant_ctor_id).unwrap();
+                Def::Variant(variant_id)
+            },
+            def => def,
+        };
+
         let mut kind = match def {
-            Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
+            Def::Variant(variant_id) => {
                 let enum_id = self.tcx.parent(variant_id).unwrap();
                 let adt_def = self.tcx.adt_def(enum_id);
                 if adt_def.is_enum() {
@@ -757,7 +765,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                 }
             }
 
-            Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
+            Def::Struct(..) | Def::Ctor(_, CtorOf::Struct, ..) | Def::Union(..) |
             Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) | Def::SelfCtor(..) => {
                 PatternKind::Leaf { subpatterns }
             }
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index f1fbc80edfb..cb25db73cd2 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -880,7 +880,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
     };
 
     let variant_no = if adt_def.is_enum() {
-        adt_def.variant_index_with_id(def_id)
+        adt_def.variant_index_with_ctor_id(def_id)
     } else {
         VariantIdx::new(0)
     };
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index 13bcdc26a5e..5e5e451b75b 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -1,5 +1,4 @@
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
-use rustc::hir::def::CtorKind;
 use rustc::mir::*;
 use rustc::mir::visit::Visitor;
 use rustc::ty::{self, TyCtxt};
@@ -587,15 +586,12 @@ fn write_mir_sig(
     trace!("write_mir_sig: {:?}", src.instance);
     let descr = tcx.describe_def(src.def_id());
     let is_function = match descr {
-        Some(Def::Fn(_)) | Some(Def::Method(_)) | Some(Def::Variant(..)) |
-        Some(Def::StructCtor(_, CtorKind::Fn)) => true,
+        Some(Def::Fn(_)) | Some(Def::Method(_)) | Some(Def::Ctor(..)) => true,
         _ => tcx.is_closure(src.def_id()),
     };
     match (descr, src.promoted) {
         (_, Some(i)) => write!(w, "{:?} in ", i)?,
-        (Some(Def::StructCtor(..)), _) => write!(w, "struct ")?,
-        (Some(Def::Const(_)), _)
-        | (Some(Def::AssociatedConst(_)), _) => write!(w, "const ")?,
+        (Some(Def::Const(_)), _) | (Some(Def::AssociatedConst(_)), _) => write!(w, "const ")?,
         (Some(Def::Static(_, /*is_mutbl*/false)), _) => write!(w, "static ")?,
         (Some(Def::Static(_, /*is_mutbl*/true)), _) => write!(w, "static mut ")?,
         (_, _) if is_function => write!(w, "fn ")?,
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index b85429cd3cf..4e2aefe6231 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -661,7 +661,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 }
             }
             ItemKind::Union(ref vdata, _) => {
-                if !vdata.is_struct() {
+                if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
                     self.err_handler().span_err(item.span,
                                                 "tuple and unit unions are not permitted");
                 }
diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs
index 6de98675a3d..71eb6ed7e05 100644
--- a/src/librustc_passes/rvalue_promotion.rs
+++ b/src/librustc_passes/rvalue_promotion.rs
@@ -322,8 +322,8 @@ fn check_expr_kind<'a, 'tcx>(
         hir::ExprKind::Path(ref qpath) => {
             let def = v.tables.qpath_def(qpath, e.hir_id);
             match def {
-                Def::VariantCtor(..) | Def::StructCtor(..) |
-                Def::Fn(..) | Def::Method(..) | Def::SelfCtor(..) => Promotable,
+                Def::Ctor(..) | Def::Fn(..) | Def::Method(..) | Def::SelfCtor(..) =>
+                    Promotable,
 
                 // References to a static that are themselves within a static
                 // are inherently promotable with the exception
@@ -387,8 +387,7 @@ fn check_expr_kind<'a, 'tcx>(
                 Def::Err
             };
             let def_result = match def {
-                Def::StructCtor(_, CtorKind::Fn) |
-                Def::VariantCtor(_, CtorKind::Fn) |
+                Def::Ctor(_, _, CtorKind::Fn) |
                 Def::SelfCtor(..) => Promotable,
                 Def::Fn(did) => v.handle_const_fn_call(did),
                 Def::Method(did) => {
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 19b5fa1bfbe..bbd03e82a37 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -239,36 +239,48 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
                         node => bug!("unexpected node kind: {:?}", node),
                     }
                 }
-                Node::StructCtor(vdata) => {
-                    let struct_hir_id = tcx.hir().get_parent_item(hir_id);
-                    let item = match tcx.hir().get_by_hir_id(struct_hir_id) {
-                        Node::Item(item) => item,
-                        node => bug!("unexpected node kind: {:?}", node),
-                    };
-                    let (mut ctor_vis, mut span, mut descr) =
-                        (ty::Visibility::from_hir(&item.vis, struct_hir_id, tcx),
-                         item.vis.span, item.vis.node.descr());
-                    for field in vdata.fields() {
-                        let field_vis = ty::Visibility::from_hir(&field.vis, hir_id, tcx);
-                        if ctor_vis.is_at_least(field_vis, tcx) {
-                            ctor_vis = field_vis;
-                            span = field.vis.span;
-                            descr = field.vis.node.descr();
+                Node::Ctor(vdata) => {
+                    let parent_hir_id = tcx.hir().get_parent_node_by_hir_id(hir_id);
+                    match tcx.hir().get_by_hir_id(parent_hir_id) {
+                        Node::Variant(..) => {
+                            let parent_did = tcx.hir().local_def_id_from_hir_id(parent_hir_id);
+                            return def_id_visibility(tcx, parent_did);
                         }
-                    }
+                        Node::Item(..) => {
+                            let item = match tcx.hir().get_by_hir_id(parent_hir_id) {
+                                Node::Item(item) => item,
+                                node => bug!("unexpected node kind: {:?}", node),
+                            };
+                            let (mut ctor_vis, mut span, mut descr) =
+                                (ty::Visibility::from_hir(&item.vis, parent_hir_id, tcx),
+                                item.vis.span, item.vis.node.descr());
+                            for field in vdata.fields() {
+                                let field_vis = ty::Visibility::from_hir(&field.vis, hir_id, tcx);
+                                if ctor_vis.is_at_least(field_vis, tcx) {
+                                    ctor_vis = field_vis;
+                                    span = field.vis.span;
+                                    descr = field.vis.node.descr();
+                                }
+                            }
 
-                    // If the structure is marked as non_exhaustive then lower the
-                    // visibility to within the crate.
-                    if ctor_vis == ty::Visibility::Public {
-                        let adt_def = tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id));
-                        if adt_def.non_enum_variant().is_field_list_non_exhaustive() {
-                            ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
-                            span = attr::find_by_name(&item.attrs, "non_exhaustive").unwrap().span;
-                            descr = "crate-visible";
+                            // If the structure is marked as non_exhaustive then lower the
+                            // visibility to within the crate.
+                            if ctor_vis == ty::Visibility::Public {
+                                let adt_def =
+                                    tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id));
+                                if adt_def.non_enum_variant().is_field_list_non_exhaustive() {
+                                    ctor_vis =
+                                        ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
+                                    span = attr::find_by_name(&item.attrs, "non_exhaustive")
+                                                .unwrap().span;
+                                    descr = "crate-visible";
+                                }
+                            }
+
+                            return (ctor_vis, span, descr);
                         }
+                        node => bug!("unexpected node kind: {:?}", node),
                     }
-
-                    return (ctor_vis, span, descr);
                 }
                 Node::Expr(expr) => {
                     return (ty::Visibility::Restricted(
@@ -504,7 +516,10 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
         match item.node {
             hir::ItemKind::Enum(ref def, _) => {
                 for variant in &def.variants {
-                    let variant_level = self.update(variant.node.data.hir_id(), item_level);
+                    let variant_level = self.update(variant.node.id, item_level);
+                    if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() {
+                        self.update(ctor_hir_id, item_level);
+                    }
                     for field in variant.node.data.fields() {
                         self.update(field.hir_id, variant_level);
                     }
@@ -523,8 +538,8 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
                 }
             }
             hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
-                if !def.is_struct() {
-                    self.update(def.hir_id(), item_level);
+                if let Some(ctor_hir_id) = def.ctor_hir_id() {
+                    self.update(ctor_hir_id, item_level);
                 }
                 for field in def.fields() {
                     if field.vis.node.is_pub() {
@@ -624,7 +639,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
                     self.reach(item.hir_id, item_level).generics().predicates();
                 }
                 for variant in &def.variants {
-                    let variant_level = self.get(variant.node.data.hir_id());
+                    let variant_level = self.get(variant.node.id);
                     if variant_level.is_some() {
                         for field in variant.node.data.fields() {
                             self.reach(field.hir_id, variant_level).ty();
@@ -1468,7 +1483,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
                      v: &'tcx hir::Variant,
                      g: &'tcx hir::Generics,
                      item_id: hir::HirId) {
-        if self.access_levels.is_reachable(v.node.data.hir_id()) {
+        if self.access_levels.is_reachable(v.node.id) {
             self.in_variant = true;
             intravisit::walk_variant(self, v, g, item_id);
             self.in_variant = false;
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index f312ef21682..f55425c3168 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -532,9 +532,10 @@ impl<'a> Resolver<'a> {
 
                 // If this is a tuple or unit struct, define a name
                 // in the value namespace as well.
-                if !struct_def.is_struct() {
-                    let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()),
-                                                   CtorKind::from_ast(struct_def));
+                if let Some(ctor_node_id) = struct_def.ctor_id() {
+                    let ctor_def = Def::Ctor(self.definitions.local_def_id(ctor_node_id),
+                                             CtorOf::Struct,
+                                             CtorKind::from_ast(struct_def));
                     self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, sp, expansion));
                     self.struct_constructors.insert(def.def_id(), (ctor_def, ctor_vis));
                 }
@@ -581,18 +582,21 @@ impl<'a> Resolver<'a> {
                                        vis: ty::Visibility,
                                        expansion: Mark) {
         let ident = variant.node.ident;
-        let def_id = self.definitions.local_def_id(variant.node.data.id());
 
         // Define a name in the type namespace.
+        let def_id = self.definitions.local_def_id(variant.node.id);
         let def = Def::Variant(def_id);
         self.define(parent, ident, TypeNS, (def, vis, variant.span, expansion));
 
         // Define a constructor name in the value namespace.
         // Braced variants, unlike structs, generate unusable names in
         // value namespace, they are reserved for possible future use.
+        // It's ok to use the variant's id as a ctor id since an
+        // error will be reported on any use of such resolution anyway.
+        let ctor_node_id = variant.node.data.ctor_id().unwrap_or(variant.node.id);
+        let ctor_def_id = self.definitions.local_def_id(ctor_node_id);
         let ctor_kind = CtorKind::from_ast(&variant.node.data);
-        let ctor_def = Def::VariantCtor(def_id, ctor_kind);
-
+        let ctor_def = Def::Ctor(ctor_def_id, CtorOf::Variant, ctor_kind);
         self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion));
     }
 
@@ -649,10 +653,11 @@ impl<'a> Resolver<'a> {
             Def::TraitAlias(..) | Def::PrimTy(..) | Def::ToolMod => {
                 self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion));
             }
-            Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::VariantCtor(..) => {
+            Def::Fn(..) | Def::Static(..) | Def::Const(..) |
+            Def::Ctor(_, CtorOf::Variant, ..) => {
                 self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, expansion));
             }
-            Def::StructCtor(def_id, ..) => {
+            Def::Ctor(def_id, CtorOf::Struct, ..) => {
                 self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, expansion));
 
                 if let Some(struct_def_id) =
diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs
index 828ffc6d320..fc8452e49ad 100644
--- a/src/librustc_resolve/error_reporting.rs
+++ b/src/librustc_resolve/error_reporting.rs
@@ -2,8 +2,7 @@ use std::cmp::Reverse;
 
 use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
 use log::debug;
-use rustc::hir::def::*;
-use rustc::hir::def::Namespace::*;
+use rustc::hir::def::{Def, CtorKind, Namespace::*};
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::session::config::nightly_options;
 use syntax::ast::{ExprKind};
@@ -417,7 +416,7 @@ impl<'a> Resolver<'a> {
             }
             (Def::Union(..), _) |
             (Def::Variant(..), _) |
-            (Def::VariantCtor(_, CtorKind::Fictive), _) if ns == ValueNS => {
+            (Def::Ctor(_, _, CtorKind::Fictive), _) if ns == ValueNS => {
                 err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
                                              path_str));
             }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 5a123e8b1a6..5d518510195 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -571,24 +571,20 @@ impl<'a> PathSource<'a> {
                 _ => false,
             },
             PathSource::Expr(..) => match def {
-                Def::StructCtor(_, CtorKind::Const) | Def::StructCtor(_, CtorKind::Fn) |
-                Def::VariantCtor(_, CtorKind::Const) | Def::VariantCtor(_, CtorKind::Fn) |
+                Def::Ctor(_, _, CtorKind::Const) | Def::Ctor(_, _, CtorKind::Fn) |
                 Def::Const(..) | Def::Static(..) | Def::Local(..) | Def::Upvar(..) |
                 Def::Fn(..) | Def::Method(..) | Def::AssociatedConst(..) |
                 Def::SelfCtor(..) | Def::ConstParam(..) => true,
                 _ => false,
             },
             PathSource::Pat => match def {
-                Def::StructCtor(_, CtorKind::Const) |
-                Def::VariantCtor(_, CtorKind::Const) |
+                Def::Ctor(_, _, CtorKind::Const) |
                 Def::Const(..) | Def::AssociatedConst(..) |
                 Def::SelfCtor(..) => true,
                 _ => false,
             },
             PathSource::TupleStruct => match def {
-                Def::StructCtor(_, CtorKind::Fn) |
-                Def::VariantCtor(_, CtorKind::Fn) |
-                Def::SelfCtor(..) => true,
+                Def::Ctor(_, _, CtorKind::Fn) | Def::SelfCtor(..) => true,
                 _ => false,
             },
             PathSource::Struct => match def {
@@ -1368,7 +1364,7 @@ impl<'a> NameBinding<'a> {
     fn is_variant(&self) -> bool {
         match self.kind {
             NameBindingKind::Def(Def::Variant(..), _) |
-            NameBindingKind::Def(Def::VariantCtor(..), _) => true,
+            NameBindingKind::Def(Def::Ctor(_, CtorOf::Variant, ..), _) => true,
             _ => false,
         }
     }
@@ -3093,16 +3089,14 @@ impl<'a> Resolver<'a> {
                         let is_syntactic_ambiguity = opt_pat.is_none() &&
                             bmode == BindingMode::ByValue(Mutability::Immutable);
                         match def {
-                            Def::StructCtor(_, CtorKind::Const) |
-                            Def::VariantCtor(_, CtorKind::Const) |
+                            Def::Ctor(_, _, CtorKind::Const) |
                             Def::Const(..) if is_syntactic_ambiguity => {
                                 // Disambiguate in favor of a unit struct/variant
                                 // or constant pattern.
                                 self.record_use(ident, ValueNS, binding.unwrap(), false);
                                 Some(PathResolution::new(def))
                             }
-                            Def::StructCtor(..) | Def::VariantCtor(..) |
-                            Def::Const(..) | Def::Static(..) => {
+                            Def::Ctor(..) | Def::Const(..) | Def::Static(..) => {
                                 // This is unambiguously a fresh binding, either syntactically
                                 // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
                                 // to something unusable as a pattern (e.g., constructor function),
@@ -4465,8 +4459,7 @@ impl<'a> Resolver<'a> {
                         // outside crate private modules => no need to check this)
                         if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
                             let did = match def {
-                                Def::StructCtor(did, _) | Def::VariantCtor(did, _) =>
-                                    self.parent(did),
+                                Def::Ctor(did, ..) => self.parent(did),
                                 _ => def.opt_def_id(),
                             };
                             candidates.push(ImportSuggestion { did, path });
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index bda59c6c46c..c2d2bd753c8 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -880,10 +880,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                 Ok(binding) => {
                     let imported_binding = this.import(binding, directive);
                     target_bindings[ns].set(Some(imported_binding));
-                    let conflict = this.try_define(parent, target, ns, imported_binding);
-                    if let Err(old_binding) = conflict {
-                        this.report_conflict(parent, target, ns, imported_binding, old_binding);
-                    }
+                    this.define(parent, target, ns, imported_binding);
                 }
             }
         });
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 76fd8b22f74..263f5acb662 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -488,8 +488,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         };
 
         let (value, fields) = match item.node {
-            ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, ..), _) |
-            ast::ItemKind::Union(ast::VariantData::Struct(ref fields, ..), _) => {
+            ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, ..), ..) |
+            ast::ItemKind::Union(ast::VariantData::Struct(ref fields, ..), ..) => {
                 let include_priv_fields = !self.save_ctxt.config.pub_only;
                 let fields_str = fields
                     .iter()
@@ -581,7 +581,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                     let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
                     if !self.span.filter_generated(name_span) {
                         let span = self.span_from_span(name_span);
-                        let id = id_from_node_id(variant.node.data.id(), &self.save_ctxt);
+                        let id = id_from_node_id(variant.node.id, &self.save_ctxt);
                         let parent = Some(id_from_node_id(item.id, &self.save_ctxt));
 
                         self.dumper.dump_def(
@@ -619,7 +619,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                     }
                     if !self.span.filter_generated(name_span) {
                         let span = self.span_from_span(name_span);
-                        let id = id_from_node_id(variant.node.data.id(), &self.save_ctxt);
+                        let id = id_from_node_id(variant.node.id, &self.save_ctxt);
                         let parent = Some(id_from_node_id(item.id, &self.save_ctxt));
 
                         self.dumper.dump_def(
@@ -648,7 +648,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
 
 
             for field in variant.node.data.fields() {
-                self.process_struct_field_def(field, variant.node.data.id());
+                self.process_struct_field_def(field, variant.node.id);
                 self.visit_ty(&field.ty);
             }
         }
@@ -957,8 +957,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                         );
                     }
                 }
-                HirDef::StructCtor(..) |
-                HirDef::VariantCtor(..) |
+                HirDef::Ctor(_, _, _) |
                 HirDef::Const(..) |
                 HirDef::AssociatedConst(..) |
                 HirDef::Struct(..) |
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 7ad5b7ce8c7..828ef802dd7 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -14,7 +14,7 @@ mod span_utils;
 mod sig;
 
 use rustc::hir;
-use rustc::hir::def::Def as HirDef;
+use rustc::hir::def::{CtorOf, Def as HirDef};
 use rustc::hir::Node;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::middle::privacy::AccessLevels;
@@ -298,7 +298,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     parent: None,
                     children: def.variants
                         .iter()
-                        .map(|v| id_from_node_id(v.node.data.id(), self))
+                        .map(|v| id_from_node_id(v.node.id, self))
                         .collect(),
                     decl_id: None,
                     docs: self.docs_for_attrs(&item.attrs),
@@ -725,16 +725,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     ref_id: id_from_node_id(id, self),
                 })
             }
-            HirDef::Static(..) |
-            HirDef::Const(..) |
-            HirDef::AssociatedConst(..) |
-            HirDef::VariantCtor(..) => {
-                Some(Ref {
-                    kind: RefKind::Variable,
-                    span,
-                    ref_id: id_from_def_id(def.def_id()),
-                })
-            }
             HirDef::Trait(def_id) if fn_type(path_seg) => {
                 Some(Ref {
                     kind: RefKind::Type,
@@ -767,7 +757,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     ref_id: id_from_def_id(def_id),
                 })
             }
-            HirDef::StructCtor(def_id, _) => {
+            HirDef::Ctor(def_id, CtorOf::Struct, ..) => {
                 // This is a reference to a tuple struct where the def_id points
                 // to an invisible constructor function. That is not a very useful
                 // def, so adjust to point to the tuple struct itself.
@@ -778,6 +768,16 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     ref_id: id_from_def_id(parent_def_id),
                 })
             }
+            HirDef::Static(..) |
+            HirDef::Const(..) |
+            HirDef::AssociatedConst(..) |
+            HirDef::Ctor(..) => {
+                Some(Ref {
+                    kind: RefKind::Variable,
+                    span,
+                    ref_id: id_from_def_id(def.def_id()),
+                })
+            }
             HirDef::Method(decl_id) => {
                 let def_id = if decl_id.is_local() {
                     let ti = self.tcx.associated_item(decl_id);
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index 6e47ae6b159..76034f32c74 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -586,7 +586,7 @@ impl Sig for ast::Path {
                     refs: vec![],
                 })
             }
-            Def::AssociatedConst(..) | Def::Variant(..) | Def::VariantCtor(..) => {
+            Def::AssociatedConst(..) | Def::Variant(..) | Def::Ctor(..) => {
                 let len = self.segments.len();
                 if len < 2 {
                     return Err("Bad path");
@@ -700,10 +700,11 @@ impl Sig for ast::StructField {
 
 
 impl Sig for ast::Variant_ {
-    fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
+    fn make(&self, offset: usize, parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
         let mut text = self.ident.to_string();
         match self.data {
-            ast::VariantData::Struct(ref fields, id, r) => {
+            ast::VariantData::Struct(ref fields, r) => {
+                let id = parent_id.unwrap();
                 let name_def = SigElement {
                     id: id_from_node_id(id, scx),
                     start: offset,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index e470748e344..3e61b175b76 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -4,7 +4,7 @@
 
 use errors::{Applicability, DiagnosticId};
 use crate::hir::{self, GenericArg, GenericArgs, ExprKind};
-use crate::hir::def::Def;
+use crate::hir::def::{CtorOf, Def};
 use crate::hir::def_id::DefId;
 use crate::hir::HirVec;
 use crate::lint;
@@ -1318,10 +1318,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                     tcx.hygienic_eq(assoc_ident, vd.ident, adt_def.did)
                 });
                 if let Some(variant_def) = variant_def {
-                    let def = Def::Variant(variant_def.did);
+                    let def = Def::Variant(variant_def.def_id);
                     if permit_variants {
                         check_type_alias_enum_variants_enabled(tcx, span);
-                        tcx.check_stability(variant_def.did, Some(hir_ref_id), span);
+                        tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span);
                         return (qself_ty, def);
                     } else {
                         variant_resolution = Some(def);
@@ -1596,7 +1596,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
 
         match def {
             // Case 1. Reference to a struct constructor.
-            Def::StructCtor(def_id, ..) |
+            Def::Ctor(def_id, CtorOf::Struct, ..) |
             Def::SelfCtor(.., def_id) => {
                 // Everything but the final segment should have no
                 // parameters at all.
@@ -1608,8 +1608,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             }
 
             // Case 2. Reference to a variant constructor.
-            Def::Variant(def_id) |
-            Def::VariantCtor(def_id, ..) => {
+            Def::Ctor(def_id, CtorOf::Variant, ..) | Def::Variant(def_id, ..) => {
                 let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap());
                 let (generics_def_id, index) = if let Some(adt_def) = adt_def {
                     debug_assert!(adt_def.is_enum());
@@ -1617,6 +1616,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 } else if last >= 1 && segments[last - 1].args.is_some() {
                     // Everything but the penultimate segment should have no
                     // parameters at all.
+                    let mut def_id = def_id;
+
+                    // `Def::Ctor` -> `Def::Variant`
+                    if let Def::Ctor(..) = def {
+                        def_id = tcx.parent(def_id).unwrap()
+                    }
+
+                    // `Def::Variant` -> `Def::Item` (enum)
                     let enum_def_id = tcx.parent(def_id).unwrap();
                     (enum_def_id, last - 1)
                 } else {
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index c30b9d65fec..5f46a5a1652 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -807,14 +807,12 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
                 report_unexpected_variant_def(tcx, &def, pat.span, qpath);
                 return tcx.types.err;
             }
-            Def::VariantCtor(_, CtorKind::Fictive) |
-            Def::VariantCtor(_, CtorKind::Fn) => {
+            Def::Ctor(_, _, CtorKind::Fictive) |
+            Def::Ctor(_, _, CtorKind::Fn) => {
                 report_unexpected_variant_def(tcx, &def, pat.span, qpath);
                 return tcx.types.err;
             }
-            Def::VariantCtor(_, CtorKind::Const) |
-            Def::StructCtor(_, CtorKind::Const) |
-            Def::SelfCtor(..) |
+            Def::Ctor(_, _, CtorKind::Const) | Def::SelfCtor(..) |
             Def::Const(..) | Def::AssociatedConst(..) => {} // OK
             _ => bug!("unexpected pattern definition: {:?}", def)
         }
@@ -876,8 +874,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
                 report_unexpected_def(def);
                 return tcx.types.err;
             }
-            Def::VariantCtor(_, CtorKind::Fn) |
-            Def::StructCtor(_, CtorKind::Fn) => {
+            Def::Ctor(_, _, CtorKind::Fn) => {
                 tcx.expect_variant_def(def)
             }
             _ => bug!("unexpected pattern definition: {:?}", def)
@@ -950,7 +947,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
         let mut inexistent_fields = vec![];
         // Typecheck each field.
         for &Spanned { node: ref field, span } in fields {
-            let ident = tcx.adjust_ident(field.ident, variant.did, self.body_id).0;
+            let ident = tcx.adjust_ident(field.ident, variant.def_id, self.body_id).0;
             let field_ty = match used_fields.entry(ident) {
                 Occupied(occupied) => {
                     struct_span_err!(tcx.sess, span, E0025,
@@ -1003,13 +1000,13 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
                                            E0026,
                                            "{} `{}` does not have {}",
                                            kind_name,
-                                           tcx.def_path_str(variant.did),
+                                           tcx.def_path_str(variant.def_id),
                                            field_names);
             if let Some((span, ident)) = inexistent_fields.last() {
                 err.span_label(*span,
                                format!("{} `{}` does not have {} field{}",
                                        kind_name,
-                                       tcx.def_path_str(variant.did),
+                                       tcx.def_path_str(variant.def_id),
                                        t,
                                        plural));
                 if plural == "" {
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 3a7308d0917..b1a249d821b 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -130,7 +130,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         let sole_field = &variant.fields[0];
                         let sole_field_ty = sole_field.ty(self.tcx, substs);
                         if self.can_coerce(expr_ty, sole_field_ty) {
-                            let variant_path = self.tcx.def_path_str(variant.did);
+                            let variant_path = self.tcx.def_path_str(variant.def_id);
                             // FIXME #56861: DRYer prelude filtering
                             Some(variant_path.trim_start_matches("std::prelude::v1::").to_string())
                         } else {
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 5e3ebcb3446..34a24308e49 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -15,7 +15,7 @@ use crate::namespace::Namespace;
 use errors::{Applicability, DiagnosticBuilder};
 use rustc_data_structures::sync::Lrc;
 use rustc::hir;
-use rustc::hir::def::Def;
+use rustc::hir::def::{CtorOf, Def};
 use rustc::hir::def_id::DefId;
 use rustc::traits;
 use rustc::ty::subst::{InternalSubsts, SubstsRef};
@@ -417,7 +417,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 if let Some(variant_def) = variant_def {
                     check_type_alias_enum_variants_enabled(tcx, span);
 
-                    let def = Def::VariantCtor(variant_def.did, variant_def.ctor_kind);
+                    // Braced variants generate unusable names in value namespace (reserved for
+                    // possible future use), so variants resolved as associated items may refer to
+                    // them as well. It's ok to use the variant's id as a ctor id since an
+                    // error will be reported on any use of such resolution anyway.
+                    let ctor_def_id = variant_def.ctor_def_id.unwrap_or(variant_def.def_id);
+                    let def = Def::Ctor(ctor_def_id, CtorOf::Variant, variant_def.ctor_kind);
                     tcx.check_stability(def.def_id(), Some(expr_id), span);
                     return Ok(def);
                 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 1054619f0f8..94f76b03a64 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -86,7 +86,7 @@ mod op;
 use crate::astconv::{AstConv, PathSeg};
 use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
 use rustc::hir::{self, ExprKind, GenericArg, ItemKind, Node, PatKind, QPath};
-use rustc::hir::def::{CtorKind, Def};
+use rustc::hir::def::{CtorOf, CtorKind, Def};
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
@@ -1863,7 +1863,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     for ((_, discr), v) in def.discriminants(tcx).zip(vs) {
         // Check for duplicate discriminant values
         if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
-            let variant_did = def.variants[VariantIdx::new(i)].did;
+            let variant_did = def.variants[VariantIdx::new(i)].def_id;
             let variant_i_hir_id = tcx.hir().as_local_hir_id(variant_did).unwrap();
             let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
             let i_span = match variant_i.node.disr_expr {
@@ -3693,7 +3693,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let names = variant.fields.iter().filter_map(|field| {
             // ignore already set fields and private fields from non-local crates
             if skip.iter().any(|x| *x == field.ident.as_str()) ||
-               (variant.did.krate != LOCAL_CRATE && field.vis != Visibility::Public) {
+               (!variant.def_id.is_local() && field.vis != Visibility::Public)
+            {
                 None
             } else {
                 Some(&field.ident.name)
@@ -3705,7 +3706,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec<ast::Name> {
         variant.fields.iter().filter(|field| {
-            let def_scope = self.tcx.adjust_ident(field.ident, variant.did, self.body_id).1;
+            let def_scope = self.tcx.adjust_ident(field.ident, variant.def_id, self.body_id).1;
             field.vis.is_accessible_from(def_scope, self.tcx)
         })
         .map(|field| field.ident.name)
@@ -3823,7 +3824,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Type-check each field.
         for field in ast_fields {
-            let ident = tcx.adjust_ident(field.ident, variant.did, self.body_id).0;
+            let ident = tcx.adjust_ident(field.ident, variant.def_id, self.body_id).0;
             let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
                 seen_fields.insert(ident, field.span);
                 self.write_field_index(field.hir_id, i);
@@ -4237,7 +4238,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         self.set_tainted_by_errors();
                         tcx.types.err
                     }
-                    Def::VariantCtor(_, CtorKind::Fictive) => {
+                    Def::Ctor(_, _, CtorKind::Fictive) => {
                         report_unexpected_variant_def(tcx, &def, expr.span, qpath);
                         tcx.types.err
                     }
@@ -5333,7 +5334,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         Some(original_span.with_lo(original_span.hi() - BytePos(1)))
     }
 
-    // Rewrite `SelfCtor` to `StructCtor`
+    // Rewrite `SelfCtor` to `Ctor`
     pub fn rewrite_self_ctor(&self, def: Def, span: Span) -> (Def, DefId, Ty<'tcx>) {
         let tcx = self.tcx;
         if let Def::SelfCtor(impl_def_id) = def {
@@ -5343,8 +5344,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             match adt_def {
                 Some(adt_def) if adt_def.has_ctor() => {
                     let variant = adt_def.non_enum_variant();
-                    let def = Def::StructCtor(variant.did, variant.ctor_kind);
-                    (def, variant.did, tcx.type_of(variant.did))
+                    let ctor_def_id = variant.ctor_def_id.unwrap();
+                    let def = Def::Ctor(ctor_def_id, CtorOf::Struct, variant.ctor_kind);
+                    (def, ctor_def_id, tcx.type_of(ctor_def_id))
                 }
                 _ => {
                     let mut err = tcx.sess.struct_span_err(span,
@@ -5416,7 +5418,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let mut user_self_ty = None;
         let mut is_alias_variant_ctor = false;
         match def {
-            Def::VariantCtor(_, _) => {
+            Def::Ctor(_, CtorOf::Variant, _) => {
                 if let Some(self_ty) = self_ty {
                     let adt_def = self_ty.ty_adt_def().unwrap();
                     user_self_ty = Some(UserSelfTy {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index c0739db3df6..06450424776 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -446,8 +446,8 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: hir::HirId) {
                 tcx.predicates_of(def_id);
             }
 
-            if !struct_def.is_struct() {
-                convert_variant_ctor(tcx, struct_def.hir_id());
+            if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
+                convert_variant_ctor(tcx, ctor_hir_id);
             }
         }
 
@@ -556,21 +556,24 @@ fn convert_enum_variant_types<'a, 'tcx>(
 
         // Convert the ctor, if any. This also registers the variant as
         // an item.
-        convert_variant_ctor(tcx, variant.node.data.hir_id());
+        if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() {
+            convert_variant_ctor(tcx, ctor_hir_id);
+        }
     }
 }
 
 fn convert_variant<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    did: DefId,
+    variant_did: Option<DefId>,
+    ctor_did: Option<DefId>,
     ident: Ident,
     discr: ty::VariantDiscr,
     def: &hir::VariantData,
     adt_kind: ty::AdtKind,
-    attribute_def_id: DefId
+    parent_did: DefId
 ) -> ty::VariantDef {
     let mut seen_fields: FxHashMap<ast::Ident, Span> = Default::default();
-    let hir_id = tcx.hir().as_local_hir_id(did).unwrap();
+    let hir_id = tcx.hir().as_local_hir_id(variant_did.unwrap_or(parent_did)).unwrap();
     let fields = def
         .fields()
         .iter()
@@ -599,17 +602,19 @@ fn convert_variant<'a, 'tcx>(
         })
         .collect();
     let recovered = match def {
-        hir::VariantData::Struct(_, _, r) => *r,
+        hir::VariantData::Struct(_, r) => *r,
         _ => false,
     };
-    ty::VariantDef::new(tcx,
-        did,
+    ty::VariantDef::new(
+        tcx,
         ident,
+        variant_did,
+        ctor_did,
         discr,
         fields,
-        adt_kind,
         CtorKind::from_hir(def),
-        attribute_def_id,
+        adt_kind,
+        parent_did,
         recovered,
     )
 }
@@ -627,58 +632,52 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Ad
     let (kind, variants) = match item.node {
         ItemKind::Enum(ref def, _) => {
             let mut distance_from_explicit = 0;
-            (
-                AdtKind::Enum,
-                def.variants
-                    .iter()
-                    .map(|v| {
-                        let did = tcx.hir().local_def_id_from_hir_id(v.node.data.hir_id());
-                        let discr = if let Some(ref e) = v.node.disr_expr {
-                            distance_from_explicit = 0;
-                            ty::VariantDiscr::Explicit(tcx.hir().local_def_id_from_hir_id(e.hir_id))
-                        } else {
-                            ty::VariantDiscr::Relative(distance_from_explicit)
-                        };
-                        distance_from_explicit += 1;
+            let variants = def.variants
+                .iter()
+                .map(|v| {
+                    let variant_did = Some(tcx.hir().local_def_id_from_hir_id(v.node.id));
+                    let ctor_did = v.node.data.ctor_hir_id()
+                        .map(|hir_id| tcx.hir().local_def_id_from_hir_id(hir_id));
+
+                    let discr = if let Some(ref e) = v.node.disr_expr {
+                        distance_from_explicit = 0;
+                        ty::VariantDiscr::Explicit(tcx.hir().local_def_id_from_hir_id(e.hir_id))
+                    } else {
+                        ty::VariantDiscr::Relative(distance_from_explicit)
+                    };
+                    distance_from_explicit += 1;
 
-                        convert_variant(tcx, did, v.node.ident, discr, &v.node.data, AdtKind::Enum,
-                                        did)
-                    })
-                    .collect(),
-            )
+                    convert_variant(tcx, variant_did, ctor_did, v.node.ident, discr,
+                                    &v.node.data, AdtKind::Enum, def_id)
+                })
+                .collect();
+
+            (AdtKind::Enum, variants)
         }
         ItemKind::Struct(ref def, _) => {
-            // Use separate constructor id for unit/tuple structs and reuse did for braced structs.
-            let ctor_id = if !def.is_struct() {
-                Some(tcx.hir().local_def_id_from_hir_id(def.hir_id()))
-            } else {
-                None
-            };
-            (
-                AdtKind::Struct,
-                std::iter::once(convert_variant(
-                    tcx,
-                    ctor_id.unwrap_or(def_id),
-                    item.ident,
-                    ty::VariantDiscr::Relative(0),
-                    def,
-                    AdtKind::Struct,
-                    def_id
-                )).collect(),
-            )
-        }
-        ItemKind::Union(ref def, _) => (
-            AdtKind::Union,
-            std::iter::once(convert_variant(
-                tcx,
-                def_id,
-                item.ident,
-                ty::VariantDiscr::Relative(0),
-                def,
-                AdtKind::Union,
-                def_id
-            )).collect(),
-        ),
+            let variant_did = None;
+            let ctor_did = def.ctor_hir_id()
+                .map(|hir_id| tcx.hir().local_def_id_from_hir_id(hir_id));
+
+            let variants = std::iter::once(convert_variant(
+                tcx, variant_did, ctor_did, item.ident, ty::VariantDiscr::Relative(0), def,
+                AdtKind::Struct, def_id,
+            )).collect();
+
+            (AdtKind::Struct, variants)
+        }
+        ItemKind::Union(ref def, _) => {
+            let variant_did = None;
+            let ctor_did = def.ctor_hir_id()
+                .map(|hir_id| tcx.hir().local_def_id_from_hir_id(hir_id));
+
+            let variants = std::iter::once(convert_variant(
+                tcx, variant_did, ctor_did, item.ident, ty::VariantDiscr::Relative(0), def,
+                AdtKind::Union, def_id,
+            )).collect();
+
+            (AdtKind::Union, variants)
+        },
         _ => bug!(),
     };
     tcx.alloc_adt_def(def_id, kind, variants, repr)
@@ -889,8 +888,8 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty
 
     let node = tcx.hir().get_by_hir_id(hir_id);
     let parent_def_id = match node {
-        Node::ImplItem(_) | Node::TraitItem(_) | Node::Variant(_)
-        | Node::StructCtor(_) | Node::Field(_) => {
+        Node::ImplItem(_) | Node::TraitItem(_) | Node::Variant(_) |
+        Node::Ctor(..) | Node::Field(_) => {
             let parent_id = tcx.hir().get_parent_item(hir_id);
             Some(tcx.hir().local_def_id_from_hir_id(parent_id))
         }
@@ -1248,8 +1247,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
             ForeignItemKind::Type => tcx.mk_foreign(def_id),
         },
 
-        Node::StructCtor(&ref def)
-        | Node::Variant(&Spanned {
+        Node::Ctor(&ref def) | Node::Variant(&Spanned {
             node: hir::VariantKind { data: ref def, .. },
             ..
         }) => match *def {
@@ -1627,17 +1625,12 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::PolyFnSig
             compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
         }
 
-        StructCtor(&VariantData::Tuple(ref fields, ..))
-        | Variant(&Spanned {
-            node:
-                hir::VariantKind {
-                    data: VariantData::Tuple(ref fields, ..),
-                    ..
-                },
+        Ctor(data) | Variant(Spanned {
+            node: hir::VariantKind { data, ..  },
             ..
-        }) => {
+        }) if data.ctor_hir_id().is_some() => {
             let ty = tcx.type_of(tcx.hir().get_parent_did_by_hir_id(hir_id));
-            let inputs = fields
+            let inputs = data.fields()
                 .iter()
                 .map(|f| tcx.type_of(tcx.hir().local_def_id_from_hir_id(f.hir_id)));
             ty::Binder::bind(tcx.mk_fn_sig(
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 20eae5d8835..f2406bd8540 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -75,7 +75,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
                 self.visit_node_helper(item.hir_id);
 
                 if let hir::VariantData::Tuple(..) = *struct_def {
-                    self.visit_node_helper(struct_def.hir_id());
+                    self.visit_node_helper(struct_def.ctor_hir_id().unwrap());
                 }
             }
 
@@ -84,7 +84,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
 
                 for variant in &enum_def.variants {
                     if let hir::VariantData::Tuple(..) = variant.node.data {
-                        self.visit_node_helper(variant.node.data.hir_id());
+                        self.visit_node_helper(variant.node.data.ctor_hir_id().unwrap());
                     }
                 }
             }
diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs
index c2f79207a56..9b9a6bace96 100644
--- a/src/librustc_typeck/variance/mod.rs
+++ b/src/librustc_typeck/variance/mod.rs
@@ -79,7 +79,7 @@ fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
             _ => unsupported()
         },
 
-        Node::Variant(_) | Node::StructCtor(_) => {}
+        Node::Variant(_) | Node::Ctor(..) => {}
 
         _ => unsupported()
     }
diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs
index 50c8d5adfa3..ac686e40076 100644
--- a/src/librustc_typeck/variance/terms.rs
+++ b/src/librustc_typeck/variance/terms.rs
@@ -136,7 +136,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
                 self.add_inferreds_for_item(item.hir_id);
 
                 if let hir::VariantData::Tuple(..) = *struct_def {
-                    self.add_inferreds_for_item(struct_def.hir_id());
+                    self.add_inferreds_for_item(struct_def.ctor_hir_id().unwrap());
                 }
             }
 
@@ -145,7 +145,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
 
                 for variant in &enum_def.variants {
                     if let hir::VariantData::Tuple(..) = variant.node.data {
-                        self.add_inferreds_for_item(variant.node.data.hir_id());
+                        self.add_inferreds_for_item(variant.node.data.ctor_hir_id().unwrap());
                     }
                 }
             }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 880f67281b9..5969aa758df 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -88,9 +88,7 @@ pub fn try_inline(
         Def::Variant(..) => return None,
         // Assume that enum variants and struct types are re-exported next to
         // their constructors.
-        Def::VariantCtor(..) |
-        Def::StructCtor(..) |
-        Def::SelfCtor(..) => return Some(Vec::new()),
+        Def::Ctor(..) | Def::SelfCtor(..) => return Some(Vec::new()),
         Def::Mod(did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Module);
             clean::ModuleItem(build_module(cx, did, visited))
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ba4481733d5..61dbf00a1f5 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -3133,7 +3133,7 @@ impl Clean<Item> for doctree::Variant {
             visibility: None,
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
-            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.def.hir_id()),
+            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id),
             inner: VariantItem(Variant {
                 kind: self.def.clean(cx),
             }),
@@ -3171,13 +3171,13 @@ impl<'tcx> Clean<Item> for ty::VariantDef {
         };
         Item {
             name: Some(self.ident.clean(cx)),
-            attrs: inline::load_attrs(cx, self.did),
-            source: cx.tcx.def_span(self.did).clean(cx),
+            attrs: inline::load_attrs(cx, self.def_id),
+            source: cx.tcx.def_span(self.def_id).clean(cx),
             visibility: Some(Inherited),
-            def_id: self.did,
+            def_id: self.def_id,
             inner: VariantItem(Variant { kind }),
-            stability: get_stability(cx, self.did),
-            deprecation: get_deprecation(cx, self.did),
+            stability: get_stability(cx, self.def_id),
+            deprecation: get_deprecation(cx, self.def_id),
         }
     }
 }
@@ -3191,12 +3191,11 @@ pub enum VariantKind {
 
 impl Clean<VariantKind> for hir::VariantData {
     fn clean(&self, cx: &DocContext<'_>) -> VariantKind {
-        if self.is_struct() {
-            VariantKind::Struct(self.clean(cx))
-        } else if self.is_unit() {
-            VariantKind::CLike
-        } else {
-            VariantKind::Tuple(self.fields().iter().map(|x| x.ty.clean(cx)).collect())
+        match self {
+            hir::VariantData::Struct(..) => VariantKind::Struct(self.clean(cx)),
+            hir::VariantData::Tuple(..) =>
+                VariantKind::Tuple(self.fields().iter().map(|x| x.ty.clean(cx)).collect()),
+            hir::VariantData::Unit(..) => VariantKind::CLike,
         }
     }
 }
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 9c54b40b422..7a528e50e9c 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -125,6 +125,7 @@ pub struct Enum {
 
 pub struct Variant {
     pub name: Name,
+    pub id: hir::HirId,
     pub attrs: hir::HirVec<ast::Attribute>,
     pub def: hir::VariantData,
     pub stab: Option<attr::Stability>,
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 7c1a61449a2..ee182237b49 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -344,9 +344,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                                 .and_then(|(def, fragment)| {
                                     // Constructors are picked up in the type namespace.
                                     match def {
-                                        Def::StructCtor(..)
-                                        | Def::VariantCtor(..)
-                                        | Def::SelfCtor(..) => None,
+                                        Def::Ctor(..) | Def::SelfCtor(..) => None,
                                         _ => Some((def, fragment))
                                     }
                                 }),
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index b4db121fb53..a7e2b2155e9 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -141,9 +141,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             name,
             variants: def.variants.iter().map(|v| Variant {
                 name: v.node.ident.name,
+                id: v.node.id,
                 attrs: v.node.attrs.clone(),
-                stab: self.stability(v.node.data.hir_id()),
-                depr: self.deprecation(v.node.data.hir_id()),
+                stab: self.stability(v.node.id),
+                depr: self.deprecation(v.node.id),
                 def: v.node.data.clone(),
                 whence: v.span,
             }).collect(),
@@ -420,8 +421,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 // Struct and variant constructors and proc macro stubs always show up alongside
                 // their definitions, we've already processed them so just discard these.
                 match path.def {
-                    Def::StructCtor(..) | Def::VariantCtor(..) | Def::SelfCtor(..) |
-                    Def::Macro(_, MacroKind::ProcMacroStub) => return,
+                    Def::Ctor(..) | Def::SelfCtor(..) | Def::Macro(_, MacroKind::ProcMacroStub) =>
+                        return,
                     _ => {}
                 }
 
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 2cbd2dfeb25..bcc8fdf8cd4 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1956,8 +1956,13 @@ pub struct EnumDef {
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Variant_ {
+    /// Name of the variant.
     pub ident: Ident,
+    /// Attributes of the variant.
     pub attrs: Vec<Attribute>,
+    /// Id of the variant (not the constructor, see `VariantData::ctor_id()`).
+    pub id: NodeId,
+    /// Fields and constructor id of the variant.
     pub data: VariantData,
     /// Explicit discriminant, e.g., `Foo = 1`.
     pub disr_expr: Option<AnonConst>,
@@ -2117,23 +2122,13 @@ pub struct StructField {
     pub attrs: Vec<Attribute>,
 }
 
-/// Fields and Ids of enum variants and structs
-///
-/// For enum variants: `NodeId` represents both an Id of the variant itself (relevant for all
-/// variant kinds) and an Id of the variant's constructor (not relevant for `Struct`-variants).
-/// One shared Id can be successfully used for these two purposes.
-/// Id of the whole enum lives in `Item`.
-///
-/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually
-/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of
-/// the variant itself" from enum variants.
-/// Id of the whole struct lives in `Item`.
+/// Fields and constructor ids of enum variants and structs.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub enum VariantData {
     /// Struct variant.
     ///
     /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
-    Struct(Vec<StructField>, NodeId, bool),
+    Struct(Vec<StructField>, bool),
     /// Tuple variant.
     ///
     /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
@@ -2145,36 +2140,19 @@ pub enum VariantData {
 }
 
 impl VariantData {
+    /// Return the fields of this variant.
     pub fn fields(&self) -> &[StructField] {
         match *self {
             VariantData::Struct(ref fields, ..) | VariantData::Tuple(ref fields, _) => fields,
             _ => &[],
         }
     }
-    pub fn id(&self) -> NodeId {
+
+    /// Return the `NodeId` of this variant's constructor, if it has one.
+    pub fn ctor_id(&self) -> Option<NodeId> {
         match *self {
-            VariantData::Struct(_, id, _) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id,
-        }
-    }
-    pub fn is_struct(&self) -> bool {
-        if let VariantData::Struct(..) = *self {
-            true
-        } else {
-            false
-        }
-    }
-    pub fn is_tuple(&self) -> bool {
-        if let VariantData::Tuple(..) = *self {
-            true
-        } else {
-            false
-        }
-    }
-    pub fn is_unit(&self) -> bool {
-        if let VariantData::Unit(..) = *self {
-            true
-        } else {
-            false
+            VariantData::Struct(..) => None,
+            VariantData::Tuple(_, id) | VariantData::Unit(id) => Some(id),
         }
     }
 }
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 7159c949513..18173628a26 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -225,10 +225,9 @@ impl<'a> StripUnconfigured<'a> {
 
     fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) {
         match vdata {
-            ast::VariantData::Struct(fields, _id, _) |
-            ast::VariantData::Tuple(fields, _id) =>
+            ast::VariantData::Struct(fields, ..) | ast::VariantData::Tuple(fields, _) =>
                 fields.flat_map_in_place(|field| self.configure(field)),
-            ast::VariantData::Unit(_id) => {}
+            ast::VariantData::Unit(_) => {}
         }
     }
 
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index e95f0589449..614967bdeb4 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -1062,6 +1062,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         respan(span,
                ast::Variant_ {
                    ident,
+                   id: ast::DUMMY_NODE_ID,
                    attrs: Vec::new(),
                    data: vdata,
                    disr_expr: None,
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 5bb1d8a4b94..784d0049ac5 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -450,9 +450,10 @@ pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis:
 }
 
 pub fn noop_visit_variant<T: MutVisitor>(variant: &mut Variant, vis: &mut T) {
-    let Spanned { node: Variant_ { ident, attrs, data, disr_expr }, span } = variant;
+    let Spanned { node: Variant_ { ident, attrs, id, data, disr_expr }, span } = variant;
     vis.visit_ident(ident);
     visit_attrs(attrs, vis);
+    vis.visit_id(id);
     vis.visit_variant_data(data);
     visit_opt(disr_expr, |disr_expr| vis.visit_anon_const(disr_expr));
     vis.visit_span(span);
@@ -765,11 +766,11 @@ pub fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis:
 
 pub fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut T) {
     match vdata {
-        VariantData::Struct(fields, id, _) |
+        VariantData::Struct(fields, ..) => visit_vec(fields, |field| vis.visit_struct_field(field)),
         VariantData::Tuple(fields, id) => {
             visit_vec(fields, |field| vis.visit_struct_field(field));
             vis.visit_id(id);
-        }
+        },
         VariantData::Unit(id) => vis.visit_id(id),
     }
 }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 99260314054..d7a2170342d 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -6844,7 +6844,7 @@ impl<'a> Parser<'a> {
             } else {
                 // If we see: `struct Foo<T> where T: Copy { ... }`
                 let (fields, recovered) = self.parse_record_struct_body()?;
-                VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
+                VariantData::Struct(fields, recovered)
             }
         // No `where` so: `struct Foo<T>;`
         } else if self.eat(&token::Semi) {
@@ -6852,7 +6852,7 @@ impl<'a> Parser<'a> {
         // Record-style struct definition
         } else if self.token == token::OpenDelim(token::Brace) {
             let (fields, recovered) = self.parse_record_struct_body()?;
-            VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
+            VariantData::Struct(fields, recovered)
         // Tuple-style struct definition with optional where-clause.
         } else if self.token == token::OpenDelim(token::Paren) {
             let body = VariantData::Tuple(self.parse_tuple_struct_body()?, ast::DUMMY_NODE_ID);
@@ -6881,10 +6881,10 @@ impl<'a> Parser<'a> {
         let vdata = if self.token.is_keyword(keywords::Where) {
             generics.where_clause = self.parse_where_clause()?;
             let (fields, recovered) = self.parse_record_struct_body()?;
-            VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
+            VariantData::Struct(fields, recovered)
         } else if self.token == token::OpenDelim(token::Brace) {
             let (fields, recovered) = self.parse_record_struct_body()?;
-            VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
+            VariantData::Struct(fields, recovered)
         } else {
             let token_str = self.this_token_descr();
             let mut err = self.fatal(&format!(
@@ -7708,7 +7708,7 @@ impl<'a> Parser<'a> {
                 // Parse a struct variant.
                 all_nullary = false;
                 let (fields, recovered) = self.parse_record_struct_body()?;
-                struct_def = VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered);
+                struct_def = VariantData::Struct(fields, recovered);
             } else if self.check(&token::OpenDelim(token::Paren)) {
                 all_nullary = false;
                 struct_def = VariantData::Tuple(
@@ -7730,6 +7730,7 @@ impl<'a> Parser<'a> {
 
             let vr = ast::Variant_ {
                 ident,
+                id: ast::DUMMY_NODE_ID,
                 attrs: variant_attrs,
                 data: struct_def,
                 disr_expr,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 07df14ddc72..f5a9aded845 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1550,44 +1550,47 @@ impl<'a> State<'a> {
                         print_finalizer: bool) -> io::Result<()> {
         self.print_ident(ident)?;
         self.print_generic_params(&generics.params)?;
-        if !struct_def.is_struct() {
-            if struct_def.is_tuple() {
-                self.popen()?;
-                self.commasep(
-                    Inconsistent, struct_def.fields(),
-                    |s, field| {
-                        s.maybe_print_comment(field.span.lo())?;
-                        s.print_outer_attributes(&field.attrs)?;
-                        s.print_visibility(&field.vis)?;
-                        s.print_type(&field.ty)
-                    }
-                )?;
-                self.pclose()?;
-            }
-            self.print_where_clause(&generics.where_clause)?;
-            if print_finalizer {
-                self.s.word(";")?;
+        match struct_def {
+            ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
+                if let ast::VariantData::Tuple(..) = struct_def {
+                    self.popen()?;
+                    self.commasep(
+                        Inconsistent, struct_def.fields(),
+                        |s, field| {
+                            s.maybe_print_comment(field.span.lo())?;
+                            s.print_outer_attributes(&field.attrs)?;
+                            s.print_visibility(&field.vis)?;
+                            s.print_type(&field.ty)
+                        }
+                    )?;
+                    self.pclose()?;
+                }
+                self.print_where_clause(&generics.where_clause)?;
+                if print_finalizer {
+                    self.s.word(";")?;
+                }
+                self.end()?;
+                self.end() // close the outer-box
             }
-            self.end()?;
-            self.end() // close the outer-box
-        } else {
-            self.print_where_clause(&generics.where_clause)?;
-            self.nbsp()?;
-            self.bopen()?;
-            self.hardbreak_if_not_bol()?;
-
-            for field in struct_def.fields() {
+            ast::VariantData::Struct(..) => {
+                self.print_where_clause(&generics.where_clause)?;
+                self.nbsp()?;
+                self.bopen()?;
                 self.hardbreak_if_not_bol()?;
-                self.maybe_print_comment(field.span.lo())?;
-                self.print_outer_attributes(&field.attrs)?;
-                self.print_visibility(&field.vis)?;
-                self.print_ident(field.ident.unwrap())?;
-                self.word_nbsp(":")?;
-                self.print_type(&field.ty)?;
-                self.s.word(",")?;
-            }
 
-            self.bclose(span)
+                for field in struct_def.fields() {
+                    self.hardbreak_if_not_bol()?;
+                    self.maybe_print_comment(field.span.lo())?;
+                    self.print_outer_attributes(&field.attrs)?;
+                    self.print_visibility(&field.vis)?;
+                    self.print_ident(field.ident.unwrap())?;
+                    self.word_nbsp(":")?;
+                    self.print_type(&field.ty)?;
+                    self.s.word(",")?;
+                }
+
+                self.bclose(span)
+            }
         }
     }
 
@@ -3266,6 +3269,7 @@ mod tests {
             let var = source_map::respan(syntax_pos::DUMMY_SP, ast::Variant_ {
                 ident,
                 attrs: Vec::new(),
+                id: ast::DUMMY_NODE_ID,
                 // making this up as I go.... ?
                 data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
                 disr_expr: None,
diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs
index 7dc2d007d73..7c47c6ff79a 100644
--- a/src/libsyntax_ext/deriving/debug.rs
+++ b/src/libsyntax_ext/deriving/debug.rs
@@ -51,9 +51,9 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
     // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build()
     // or fmt.debug_tuple(<name>).field(&<fieldval>)....build()
     // based on the "shape".
-    let (ident, is_struct) = match *substr.fields {
-        Struct(vdata, _) => (substr.type_ident, vdata.is_struct()),
-        EnumMatching(_, _, v, _) => (v.node.ident, v.node.data.is_struct()),
+    let (ident, vdata, fields) = match substr.fields {
+        Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
+        EnumMatching(_, _, v, fields) => (v.node.ident, &v.node.data, fields),
         EnumNonMatchingCollapsed(..) |
         StaticStruct(..) |
         StaticEnum(..) => cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"),
@@ -67,55 +67,51 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
 
     let fmt = substr.nonself_args[0].clone();
 
-    let mut stmts = match *substr.fields {
-        Struct(_, ref fields) |
-        EnumMatching(.., ref fields) => {
-            let mut stmts = vec![];
-            if !is_struct {
-                // tuple struct/"normal" variant
-                let expr =
-                    cx.expr_method_call(span, fmt, Ident::from_str("debug_tuple"), vec![name]);
-                stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
-
-                for field in fields {
-                    // Use double indirection to make sure this works for unsized types
-                    let field = cx.expr_addr_of(field.span, field.self_.clone());
-                    let field = cx.expr_addr_of(field.span, field);
-
-                    let expr = cx.expr_method_call(span,
-                                                   builder_expr.clone(),
-                                                   Ident::from_str("field"),
-                                                   vec![field]);
-
-                    // Use `let _ = expr;` to avoid triggering the
-                    // unused_results lint.
-                    stmts.push(stmt_let_undescore(cx, span, expr));
-                }
-            } else {
-                // normal struct/struct variant
-                let expr =
-                    cx.expr_method_call(span, fmt, Ident::from_str("debug_struct"), vec![name]);
-                stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
-
-                for field in fields {
-                    let name = cx.expr_lit(field.span,
-                                           ast::LitKind::Str(field.name.unwrap().name,
-                                                             ast::StrStyle::Cooked));
-
-                    // Use double indirection to make sure this works for unsized types
-                    let field = cx.expr_addr_of(field.span, field.self_.clone());
-                    let field = cx.expr_addr_of(field.span, field);
-                    let expr = cx.expr_method_call(span,
-                                                   builder_expr.clone(),
-                                                   Ident::from_str("field"),
-                                                   vec![name, field]);
-                    stmts.push(stmt_let_undescore(cx, span, expr));
-                }
+    let mut stmts = vec![];
+    match vdata {
+        ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
+            // tuple struct/"normal" variant
+            let expr =
+                cx.expr_method_call(span, fmt, Ident::from_str("debug_tuple"), vec![name]);
+            stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
+
+            for field in fields {
+                // Use double indirection to make sure this works for unsized types
+                let field = cx.expr_addr_of(field.span, field.self_.clone());
+                let field = cx.expr_addr_of(field.span, field);
+
+                let expr = cx.expr_method_call(span,
+                                                builder_expr.clone(),
+                                                Ident::from_str("field"),
+                                                vec![field]);
+
+                // Use `let _ = expr;` to avoid triggering the
+                // unused_results lint.
+                stmts.push(stmt_let_undescore(cx, span, expr));
             }
-            stmts
         }
-        _ => unreachable!(),
-    };
+        ast::VariantData::Struct(..) => {
+            // normal struct/struct variant
+            let expr =
+                cx.expr_method_call(span, fmt, Ident::from_str("debug_struct"), vec![name]);
+            stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
+
+            for field in fields {
+                let name = cx.expr_lit(field.span,
+                                        ast::LitKind::Str(field.name.unwrap().name,
+                                                            ast::StrStyle::Cooked));
+
+                // Use double indirection to make sure this works for unsized types
+                let field = cx.expr_addr_of(field.span, field.self_.clone());
+                let field = cx.expr_addr_of(field.span, field);
+                let expr = cx.expr_method_call(span,
+                                                builder_expr.clone(),
+                                                Ident::from_str("field"),
+                                                vec![name, field]);
+                stmts.push(stmt_let_undescore(cx, span, expr));
+            }
+        }
+    }
 
     let expr = cx.expr_method_call(span, builder_expr, Ident::from_str("finish"), vec![]);
 
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 2bb98c1bf62..dc0d72a7830 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -1539,6 +1539,7 @@ impl<'a> TraitDef<'a> {
             }
         }
 
+        let is_tuple = if let ast::VariantData::Tuple(..) = struct_def { true } else { false };
         match (just_spans.is_empty(), named_idents.is_empty()) {
             (false, false) => {
                 cx.span_bug(self.span,
@@ -1547,9 +1548,10 @@ impl<'a> TraitDef<'a> {
             }
             // named fields
             (_, false) => Named(named_idents),
-            // empty structs
-            _ if struct_def.is_struct() => Named(named_idents),
-            _ => Unnamed(just_spans, struct_def.is_tuple()),
+            // unnamed fields
+            (false, _) => Unnamed(just_spans, is_tuple),
+            // empty
+            _ => Named(Vec::new()),
         }
     }
 
diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs
index ef41373d774..606503151c9 100644
--- a/src/test/mir-opt/unusual-item-types.rs
+++ b/src/test/mir-opt/unusual-item-types.rs
@@ -72,7 +72,7 @@ fn main() {
 // }
 // END rustc.ptr-real_drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir
 
-// START rustc.Test-X.mir_map.0.mir
+// START rustc.Test-X-{{constructor}}.mir_map.0.mir
 // fn Test::X(_1: usize) -> Test {
 //     let mut _0: Test;
 //
@@ -81,4 +81,4 @@ fn main() {
 //         return;
 //     }
 // }
-// END rustc.Test-X.mir_map.0.mir
+// END rustc.Test-X-{{constructor}}.mir_map.0.mir