diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index fa745a8e08b..54bd25d6471 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2675,7 +2675,7 @@ impl VariantData {
     }
 
     /// Return the `NodeId` of this variant's constructor, if it has one.
-    pub fn ctor_id(&self) -> Option<NodeId> {
+    pub fn ctor_node_id(&self) -> Option<NodeId> {
         match *self {
             VariantData::Struct(..) => None,
             VariantData::Tuple(_, id) | VariantData::Unit(id) => Some(id),
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 7f26af67c71..4c3216d9878 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -350,7 +350,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     } else {
                         def.non_enum_variant()
                     };
-                    if !including_tuple_field.0 && variant.ctor_kind == CtorKind::Fn {
+                    if !including_tuple_field.0 && variant.ctor_kind() == Some(CtorKind::Fn) {
                         return None;
                     }
                     Some(variant.fields[field.index()].name.to_string())
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 163ccd9460c..d87117dffdc 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -998,7 +998,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
                 .iter()
                 .enumerate()
                 .map(|(i, f)| {
-                    let field_name = if variant_def.ctor_kind == CtorKind::Fn {
+                    let field_name = if variant_def.ctor_kind() == Some(CtorKind::Fn) {
                         // This is a tuple struct
                         tuple_field_name(i)
                     } else {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
index cb558a50d91..564ab351bd4 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -269,7 +269,7 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
         |cx, struct_type_di_node| {
             (0..variant_layout.fields.count())
                 .map(|field_index| {
-                    let field_name = if variant_def.ctor_kind != CtorKind::Fn {
+                    let field_name = if variant_def.ctor_kind() != Some(CtorKind::Fn) {
                         // Fields have names
                         Cow::from(variant_def.fields[field_index].name.as_str())
                     } else {
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 4ef4aad902c..149cf4ece37 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -28,8 +28,6 @@ pub enum CtorKind {
     Fn,
     /// Constructor constant automatically created by a unit struct/variant.
     Const,
-    /// Unusable name in value namespace created by a struct variant.
-    Fictive,
 }
 
 /// An attribute that is not a macro; e.g., `#[inline]` or `#[rustfmt::skip]`.
@@ -132,13 +130,9 @@ impl DefKind {
             DefKind::Variant => "variant",
             DefKind::Ctor(CtorOf::Variant, CtorKind::Fn) => "tuple variant",
             DefKind::Ctor(CtorOf::Variant, CtorKind::Const) => "unit variant",
-            DefKind::Ctor(CtorOf::Variant, CtorKind::Fictive) => "struct variant",
             DefKind::Struct => "struct",
             DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) => "tuple struct",
             DefKind::Ctor(CtorOf::Struct, CtorKind::Const) => "unit struct",
-            DefKind::Ctor(CtorOf::Struct, CtorKind::Fictive) => {
-                panic!("impossible struct constructor")
-            }
             DefKind::OpaqueTy => "opaque type",
             DefKind::ImplTraitPlaceholder => "opaque type in trait",
             DefKind::TyAlias => "type alias",
@@ -562,19 +556,11 @@ impl<T> PerNS<Option<T>> {
 }
 
 impl CtorKind {
-    pub fn from_ast(vdata: &ast::VariantData) -> CtorKind {
+    pub fn from_ast(vdata: &ast::VariantData) -> Option<(CtorKind, NodeId)> {
         match *vdata {
-            ast::VariantData::Tuple(..) => CtorKind::Fn,
-            ast::VariantData::Unit(..) => CtorKind::Const,
-            ast::VariantData::Struct(..) => CtorKind::Fictive,
-        }
-    }
-
-    pub fn from_hir(vdata: &hir::VariantData<'_>) -> CtorKind {
-        match *vdata {
-            hir::VariantData::Tuple(..) => CtorKind::Fn,
-            hir::VariantData::Unit(..) => CtorKind::Const,
-            hir::VariantData::Struct(..) => CtorKind::Fictive,
+            ast::VariantData::Tuple(_, node_id) => Some((CtorKind::Fn, node_id)),
+            ast::VariantData::Unit(node_id) => Some((CtorKind::Const, node_id)),
+            ast::VariantData::Struct(..) => None,
         }
     }
 }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index e0a38645065..bd5b93293a9 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2913,20 +2913,29 @@ impl<'hir> VariantData<'hir> {
         }
     }
 
-    /// Return the `LocalDefId` of this variant's constructor, if it has one.
-    pub fn ctor_def_id(&self) -> Option<LocalDefId> {
+    pub fn ctor(&self) -> Option<(CtorKind, HirId, LocalDefId)> {
         match *self {
-            VariantData::Struct(_, _) => None,
-            VariantData::Tuple(_, _, def_id) | VariantData::Unit(_, def_id) => Some(def_id),
+            VariantData::Tuple(_, hir_id, def_id) => Some((CtorKind::Fn, hir_id, def_id)),
+            VariantData::Unit(hir_id, def_id) => Some((CtorKind::Const, hir_id, def_id)),
+            VariantData::Struct(..) => None,
         }
     }
 
+    #[inline]
+    pub fn ctor_kind(&self) -> Option<CtorKind> {
+        self.ctor().map(|(kind, ..)| kind)
+    }
+
     /// Return the `HirId` of this variant's constructor, if it has one.
+    #[inline]
     pub fn ctor_hir_id(&self) -> Option<HirId> {
-        match *self {
-            VariantData::Struct(_, _) => None,
-            VariantData::Tuple(_, hir_id, _) | VariantData::Unit(hir_id, _) => Some(hir_id),
-        }
+        self.ctor().map(|(_, hir_id, _)| hir_id)
+    }
+
+    /// Return the `LocalDefId` of this variant's constructor, if it has one.
+    #[inline]
+    pub fn ctor_def_id(&self) -> Option<LocalDefId> {
+        self.ctor().map(|(.., def_id)| def_id)
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 33b9c61993a..069b405423c 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1165,7 +1165,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
     }
 
     if def.repr().int.is_none() {
-        let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind, CtorKind::Const);
+        let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind(), Some(CtorKind::Const));
         let has_disr = |var: &ty::VariantDef| matches!(var.discr, ty::VariantDiscr::Explicit(_));
 
         let has_non_units = def.variants().iter().any(|var| !is_unit(var));
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index a738ee4a148..9b8cc884e18 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -24,7 +24,6 @@ use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
 use rustc_hir as hir;
-use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
@@ -794,7 +793,7 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
 
         // Convert the ctor, if any. This also registers the variant as
         // an item.
-        if let Some(ctor_def_id) = variant.ctor_def_id {
+        if let Some(ctor_def_id) = variant.ctor_def_id() {
             convert_variant_ctor(tcx, ctor_def_id.expect_local());
         }
     }
@@ -803,7 +802,6 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
 fn convert_variant(
     tcx: TyCtxt<'_>,
     variant_did: Option<LocalDefId>,
-    ctor_did: Option<LocalDefId>,
     ident: Ident,
     discr: ty::VariantDiscr,
     def: &hir::VariantData<'_>,
@@ -840,10 +838,9 @@ fn convert_variant(
     ty::VariantDef::new(
         ident.name,
         variant_did.map(LocalDefId::to_def_id),
-        ctor_did.map(LocalDefId::to_def_id),
+        def.ctor().map(|(kind, _, def_id)| (kind, def_id.to_def_id())),
         discr,
         fields,
-        CtorKind::from_hir(def),
         adt_kind,
         parent_did.to_def_id(),
         recovered,
@@ -882,7 +879,6 @@ fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
                     convert_variant(
                         tcx,
                         Some(v.def_id),
-                        v.data.ctor_def_id(),
                         v.ident,
                         discr,
                         &v.data,
@@ -894,35 +890,23 @@ fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
 
             (AdtKind::Enum, variants)
         }
-        ItemKind::Struct(ref def, _) => {
+        ItemKind::Struct(ref def, _) | ItemKind::Union(ref def, _) => {
+            let adt_kind = match item.kind {
+                ItemKind::Struct(..) => AdtKind::Struct,
+                _ => AdtKind::Union,
+            };
             let variants = std::iter::once(convert_variant(
                 tcx,
                 None,
-                def.ctor_def_id(),
                 item.ident,
                 ty::VariantDiscr::Relative(0),
                 def,
-                AdtKind::Struct,
+                adt_kind,
                 def_id,
             ))
             .collect();
 
-            (AdtKind::Struct, variants)
-        }
-        ItemKind::Union(ref def, _) => {
-            let variants = std::iter::once(convert_variant(
-                tcx,
-                None,
-                def.ctor_def_id(),
-                item.ident,
-                ty::VariantDiscr::Relative(0),
-                def,
-                AdtKind::Union,
-                def_id,
-            ))
-            .collect();
-
-            (AdtKind::Union, variants)
+            (adt_kind, variants)
         }
         _ => bug!(),
     };
@@ -1171,7 +1155,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
             compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi)
         }
 
-        Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor_hir_id().is_some() => {
+        Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => {
             let ty = tcx.type_of(tcx.hir().get_parent_item(hir_id));
             let inputs = data.fields().iter().map(|f| tcx.type_of(f.def_id));
             ty::Binder::dummy(tcx.mk_fn_sig(
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index eaf0310d57a..6ce0c18bf45 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -72,8 +72,8 @@ pub fn add_constraints_from_crate<'a, 'tcx>(
 
                 let adt = tcx.adt_def(def_id);
                 for variant in adt.variants() {
-                    if let Some(ctor) = variant.ctor_def_id {
-                        constraint_cx.build_constraints_for_item(ctor.expect_local());
+                    if let Some(ctor_def_id) = variant.ctor_def_id() {
+                        constraint_cx.build_constraints_for_item(ctor_def_id.expect_local());
                     }
                 }
             }
diff --git a/compiler/rustc_hir_analysis/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs
index 1f763011e06..58e8f474761 100644
--- a/compiler/rustc_hir_analysis/src/variance/terms.rs
+++ b/compiler/rustc_hir_analysis/src/variance/terms.rs
@@ -91,8 +91,8 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(
 
                 let adt = tcx.adt_def(def_id);
                 for variant in adt.variants() {
-                    if let Some(ctor) = variant.ctor_def_id {
-                        terms_cx.add_inferreds_for_item(ctor.expect_local());
+                    if let Some(ctor_def_id) = variant.ctor_def_id() {
+                        terms_cx.add_inferreds_for_item(ctor_def_id.expect_local());
                     }
                 }
             }
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 302d512c71d..42aa3bcee49 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -6,7 +6,7 @@ use crate::type_error_struct;
 use rustc_ast::util::parser::PREC_POSTFIX;
 use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey};
 use rustc_hir as hir;
-use rustc_hir::def::{self, Namespace, Res};
+use rustc_hir::def::{self, CtorKind, Namespace, Res};
 use rustc_hir::def_id::DefId;
 use rustc_infer::{
     infer,
@@ -595,7 +595,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) {
         let mut unit_variant = None;
         if let hir::ExprKind::Path(qpath) = &callee_expr.kind
-            && let Res::Def(def::DefKind::Ctor(kind, def::CtorKind::Const), _)
+            && let Res::Def(def::DefKind::Ctor(kind, CtorKind::Const), _)
                 = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
             // Only suggest removing parens if there are no arguments
             && arg_exprs.is_empty()
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 5a34ab40174..934d1240442 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -2,6 +2,7 @@ use crate::FnCtxt;
 use rustc_ast::util::parser::PREC_POSTFIX;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
+use rustc_hir::def::CtorKind;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{is_range_literal, Node};
 use rustc_infer::infer::InferOk;
@@ -404,27 +405,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         if let Some(path) = variant_path.strip_prefix("std::prelude::")
                             && let Some((_, path)) = path.split_once("::")
                         {
-                            return Some((path.to_string(), variant.ctor_kind, sole_field.name, note_about_variant_field_privacy));
+                            return Some((path.to_string(), variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy));
                         }
-                        Some((variant_path, variant.ctor_kind, sole_field.name, note_about_variant_field_privacy))
+                        Some((variant_path, variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy))
                     } else {
                         None
                     }
                 })
                 .collect();
 
-            let suggestions_for = |variant: &_, ctor, field_name| {
+            let suggestions_for = |variant: &_, ctor_kind, field_name| {
                 let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
                     Some(ident) => format!("{ident}: "),
                     None => String::new(),
                 };
 
-                let (open, close) = match ctor {
-                    hir::def::CtorKind::Fn => ("(".to_owned(), ")"),
-                    hir::def::CtorKind::Fictive => (format!(" {{ {field_name}: "), " }"),
+                let (open, close) = match ctor_kind {
+                    Some(CtorKind::Fn) => ("(".to_owned(), ")"),
+                    None => (format!(" {{ {field_name}: "), " }"),
 
                     // unit variants don't have fields
-                    hir::def::CtorKind::Const => unreachable!(),
+                    Some(CtorKind::Const) => unreachable!(),
                 };
 
                 // Suggest constructor as deep into the block tree as possible.
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index de30bfe6923..886a3ad755d 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -533,8 +533,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.set_tainted_by_errors(e);
                 tcx.ty_error_with_guaranteed(e)
             }
-            Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) => {
-                let e = report_unexpected_variant_res(tcx, res, qpath, expr.span);
+            Res::Def(DefKind::Variant, _) => {
+                let e = report_unexpected_variant_res(tcx, res, qpath, expr.span, "E0533", "value");
                 tcx.ty_error_with_guaranteed(e)
             }
             _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0,
@@ -2024,8 +2024,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         );
 
         let variant_ident_span = self.tcx.def_ident_span(variant.def_id).unwrap();
-        match variant.ctor_kind {
-            CtorKind::Fn => match ty.kind() {
+        match variant.ctor_kind() {
+            Some(CtorKind::Fn) => match ty.kind() {
                 ty::Adt(adt, ..) if adt.is_enum() => {
                     err.span_label(
                         variant_ident_span,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index b85a2325728..38499907663 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1164,11 +1164,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             match *ty.kind() {
                 ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
                     let variant = adt_def.non_enum_variant();
-                    let ctor_def_id = variant.ctor_def_id.unwrap();
-                    (
-                        Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id),
-                        Some(substs),
-                    )
+                    let (ctor_kind, ctor_def_id) = variant.ctor.unwrap();
+                    (Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id), Some(substs))
                 }
                 _ => {
                     let mut err = tcx.sess.struct_span_err(
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 334d6d0aa6c..5104b448023 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -53,9 +53,9 @@ use crate::check::check_fn;
 use crate::coercion::DynamicCoerceMany;
 use crate::gather_locals::GatherLocalsVisitor;
 use rustc_data_structures::unord::UnordSet;
-use rustc_errors::{struct_span_err, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{struct_span_err, DiagnosticId, ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
-use rustc_hir::def::Res;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{HirIdMap, Node};
 use rustc_hir_analysis::astconv::AstConv;
@@ -433,15 +433,27 @@ fn report_unexpected_variant_res(
     res: Res,
     qpath: &hir::QPath<'_>,
     span: Span,
+    err_code: &str,
+    expected: &str,
 ) -> ErrorGuaranteed {
-    struct_span_err!(
-        tcx.sess,
+    let res_descr = match res {
+        Res::Def(DefKind::Variant, _) => "struct variant",
+        _ => res.descr(),
+    };
+    let path_str = rustc_hir_pretty::qpath_to_string(qpath);
+    let mut err = tcx.sess.struct_span_err_with_code(
         span,
-        E0533,
-        "expected unit struct, unit variant or constant, found {} `{}`",
-        res.descr(),
-        rustc_hir_pretty::qpath_to_string(qpath),
-    )
+        format!("expected {expected}, found {res_descr} `{path_str}`"),
+        DiagnosticId::Error(err_code.into()),
+    );
+    match res {
+        Res::Def(DefKind::Fn | DefKind::AssocFn, _) if err_code == "E0164" => {
+            let patterns_url = "https://doc.rust-lang.org/book/ch18-00-patterns.html";
+            err.span_label(span, "`fn` calls are not allowed in patterns");
+            err.help(format!("for more information, visit {patterns_url}"))
+        }
+        _ => err.span_label(span, format!("not a {expected}")),
+    }
     .emit()
 }
 
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 37336edd1fd..9b1f0cff074 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -566,6 +566,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let tcx = self.tcx;
 
         // Check if we have an enum variant.
+        let mut struct_variant = None;
         if let ty::Adt(adt_def, _) = self_ty.kind() {
             if adt_def.is_enum() {
                 let variant_def = adt_def
@@ -573,16 +574,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .iter()
                     .find(|vd| tcx.hygienic_eq(method_name, vd.ident(tcx), adt_def.did()));
                 if let Some(variant_def) = variant_def {
-                    // 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);
-                    tcx.check_stability(ctor_def_id, Some(expr_id), span, Some(method_name.span));
-                    return Ok((
-                        DefKind::Ctor(CtorOf::Variant, variant_def.ctor_kind),
-                        ctor_def_id,
-                    ));
+                    if let Some((ctor_kind, ctor_def_id)) = variant_def.ctor {
+                        tcx.check_stability(
+                            ctor_def_id,
+                            Some(expr_id),
+                            span,
+                            Some(method_name.span),
+                        );
+                        return Ok((DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id));
+                    } else {
+                        struct_variant = Some((DefKind::Variant, variant_def.def_id));
+                    }
                 }
             }
         }
@@ -594,7 +596,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self_ty,
             expr_id,
             ProbeScope::TraitsInScope,
-        )?;
+        );
+        let pick = match (pick, struct_variant) {
+            // Fall back to a resolution that will produce an error later.
+            (Err(_), Some(res)) => return Ok(res),
+            (pick, _) => pick?,
+        };
 
         pick.maybe_emit_unstable_name_collision_hint(self.tcx, span, expr_id);
 
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 1d021f19104..2fe1b1d8999 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -853,8 +853,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.set_tainted_by_errors(e);
                 return tcx.ty_error_with_guaranteed(e);
             }
-            Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fictive | CtorKind::Fn), _) => {
-                let e = report_unexpected_variant_res(tcx, res, qpath, pat.span);
+            Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
+                let expected = "unit struct, unit variant or constant";
+                let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, "E0533", expected);
                 return tcx.ty_error_with_guaranteed(e);
             }
             Res::SelfCtor(..)
@@ -1002,30 +1003,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         };
         let report_unexpected_res = |res: Res| {
-            let sm = tcx.sess.source_map();
-            let path_str = sm
-                .span_to_snippet(sm.span_until_char(pat.span, '('))
-                .map_or_else(|_| String::new(), |s| format!(" `{}`", s.trim_end()));
-            let msg = format!(
-                "expected tuple struct or tuple variant, found {}{}",
-                res.descr(),
-                path_str
-            );
-
-            let mut err = struct_span_err!(tcx.sess, pat.span, E0164, "{msg}");
-            match res {
-                Res::Def(DefKind::Fn | DefKind::AssocFn, _) => {
-                    err.span_label(pat.span, "`fn` calls are not allowed in patterns");
-                    err.help(
-                        "for more information, visit \
-                              https://doc.rust-lang.org/book/ch18-00-patterns.html",
-                    );
-                }
-                _ => {
-                    err.span_label(pat.span, "not a tuple variant or struct");
-                }
-            }
-            let e = err.emit();
+            let expected = "tuple struct or tuple variant";
+            let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, "E0164", expected);
             on_error(e);
             e
         };
@@ -1481,8 +1460,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // if this is a tuple struct, then all field names will be numbers
         // so if any fields in a struct pattern use shorthand syntax, they will
         // be invalid identifiers (for example, Foo { 0, 1 }).
-        if let (CtorKind::Fn, PatKind::Struct(qpath, field_patterns, ..)) =
-            (variant.ctor_kind, &pat.kind)
+        if let (Some(CtorKind::Fn), PatKind::Struct(qpath, field_patterns, ..)) =
+            (variant.ctor_kind(), &pat.kind)
         {
             let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
             if has_shorthand_field_name {
@@ -1659,7 +1638,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         fields: &'tcx [hir::PatField<'tcx>],
         variant: &ty::VariantDef,
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
-        if let (CtorKind::Fn, PatKind::Struct(qpath, ..)) = (variant.ctor_kind, &pat.kind) {
+        if let (Some(CtorKind::Fn), PatKind::Struct(qpath, ..)) = (variant.ctor_kind(), &pat.kind) {
             let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
                 s.print_qpath(qpath, false)
             });
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index b8aff69b371..613a05e415f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -65,7 +65,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg};
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
 use rustc_hir as hir;
-use rustc_hir::def::DefKind;
+use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
@@ -1967,7 +1967,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     .variants()
                     .iter()
                     .filter(|variant| {
-                        variant.fields.len() == 1 && variant.ctor_kind == hir::def::CtorKind::Fn
+                        variant.fields.len() == 1 && variant.ctor_kind() == Some(CtorKind::Fn)
                     })
                     .filter_map(|variant| {
                         let sole_field = &variant.fields[0];
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index fc760ee3b8f..a7a4d0ca527 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -159,8 +159,8 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
     }
 
     fn visit_variant_data(&mut self, s: &'a ast::VariantData) {
-        if let Some(ctor_hir_id) = s.ctor_id() {
-            self.check_id(ctor_hir_id);
+        if let Some(ctor_node_id) = s.ctor_node_id() {
+            self.check_id(ctor_node_id);
         }
         ast_visit::walk_struct_def(self, s);
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 8e80d794a13..ac4b5126190 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -11,7 +11,7 @@ use rustc_data_structures::sync::{Lock, LockGuard, Lrc, OnceCell};
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro};
-use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
+use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
 use rustc_hir::diagnostic_items::DiagnosticItems;
@@ -31,7 +31,7 @@ use rustc_session::cstore::{
 use rustc_session::Session;
 use rustc_span::hygiene::{ExpnIndex, MacroKind};
 use rustc_span::source_map::{respan, Spanned};
-use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::{self, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP};
 
 use proc_macro::bridge::client::ProcMacro;
@@ -866,12 +866,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
 
         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));
+        let ctor = data.ctor.map(|(kind, index)| (kind, self.local_def_id(index)));
 
         ty::VariantDef::new(
             self.item_name(index),
             variant_did,
-            ctor_did,
+            ctor,
             data.discr,
             self.root
                 .tables
@@ -885,7 +885,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                     vis: self.get_visibility(index),
                 })
                 .collect(),
-            data.ctor_kind,
             adt_kind,
             parent_did,
             false,
@@ -1041,29 +1040,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                 };
 
                 callback(ModChild { ident, res, vis, span, macro_rules });
-
-                // For non-reexport variants add their fictive constructors to children.
-                // 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.
-                // Reexport lists automatically contain such constructors when necessary.
-                if kind == DefKind::Variant && self.get_ctor_def_id_and_kind(child_index).is_none()
-                {
-                    let ctor_res =
-                        Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fictive), def_id);
-                    let mut vis = vis;
-                    if vis.is_public() {
-                        // For non-exhaustive variants lower the constructor visibility to
-                        // within the crate. We only need this for fictive constructors,
-                        // for other constructors correct visibilities
-                        // were already encoded in metadata.
-                        let mut attrs = self.get_item_attrs(def_id.index, sess);
-                        if attrs.any(|item| item.has_name(sym::non_exhaustive)) {
-                            vis = ty::Visibility::Restricted(self.local_def_id(CRATE_DEF_INDEX));
-                        }
-                    }
-                    callback(ModChild { ident, res: ctor_res, vis, span, macro_rules: false });
-                }
             }
         }
 
@@ -1136,11 +1112,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         }
     }
 
-    fn get_ctor_def_id_and_kind(self, node_id: DefIndex) -> Option<(DefId, CtorKind)> {
+    fn get_ctor(self, node_id: DefIndex) -> Option<(CtorKind, DefId)> {
         match self.def_kind(node_id) {
             DefKind::Struct | DefKind::Variant => {
                 let vdata = self.root.tables.variant_data.get(self, node_id).unwrap().decode(self);
-                vdata.ctor.map(|index| (self.local_def_id(index), vdata.ctor_kind))
+                vdata.ctor.map(|(kind, index)| (kind, self.local_def_id(index)))
             }
             _ => None,
         }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index f475b0b3981..d96252ba569 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -495,8 +495,8 @@ impl CStore {
         self.get_crate_data(def.krate).get_struct_field_visibilities(def.index)
     }
 
-    pub fn ctor_def_id_and_kind_untracked(&self, def: DefId) -> Option<(DefId, CtorKind)> {
-        self.get_crate_data(def.krate).get_ctor_def_id_and_kind(def.index)
+    pub fn ctor_untracked(&self, def: DefId) -> Option<(CtorKind, DefId)> {
+        self.get_crate_data(def.krate).get_ctor(def.index)
     }
 
     pub fn visibility_untracked(&self, def: DefId) -> Visibility<DefId> {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 76a7fb41e6c..af4be12fe3a 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1221,9 +1221,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         debug!("EncodeContext::encode_enum_variant_info({:?})", def_id);
 
         let data = VariantData {
-            ctor_kind: variant.ctor_kind,
             discr: variant.discr,
-            ctor: variant.ctor_def_id.map(|did| did.index),
+            ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)),
             is_non_exhaustive: variant.is_field_list_non_exhaustive(),
         };
 
@@ -1233,32 +1232,28 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             assert!(f.did.is_local());
             f.did.index
         }));
-        if variant.ctor_kind == CtorKind::Fn {
+        if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor {
             // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
-            if let Some(ctor_def_id) = variant.ctor_def_id {
-                record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(ctor_def_id));
-            }
+            record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(ctor_def_id));
         }
     }
 
     fn encode_enum_variant_ctor(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) {
-        let tcx = self.tcx;
         let variant = &def.variant(index);
-        let def_id = variant.ctor_def_id.unwrap();
+        let Some((ctor_kind, def_id)) = variant.ctor else { return };
         debug!("EncodeContext::encode_enum_variant_ctor({:?})", def_id);
 
         // FIXME(eddyb) encode only the `CtorKind` for constructors.
         let data = VariantData {
-            ctor_kind: variant.ctor_kind,
             discr: variant.discr,
-            ctor: Some(def_id.index),
+            ctor: Some((ctor_kind, def_id.index)),
             is_non_exhaustive: variant.is_field_list_non_exhaustive(),
         };
 
         record!(self.tables.variant_data[def_id] <- data);
         self.tables.constness.set(def_id.index, hir::Constness::Const);
-        if variant.ctor_kind == CtorKind::Fn {
-            record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
+        if ctor_kind == CtorKind::Fn {
+            record!(self.tables.fn_sig[def_id] <- self.tcx.fn_sig(def_id));
         }
     }
 
@@ -1313,23 +1308,22 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
     }
 
-    fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>, def_id: DefId) {
-        debug!("EncodeContext::encode_struct_ctor({:?})", def_id);
-        let tcx = self.tcx;
+    fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>) {
         let variant = adt_def.non_enum_variant();
+        let Some((ctor_kind, def_id)) = variant.ctor else { return };
+        debug!("EncodeContext::encode_struct_ctor({:?})", def_id);
 
         let data = VariantData {
-            ctor_kind: variant.ctor_kind,
             discr: variant.discr,
-            ctor: Some(def_id.index),
+            ctor: Some((ctor_kind, def_id.index)),
             is_non_exhaustive: variant.is_field_list_non_exhaustive(),
         };
 
         record!(self.tables.repr_options[def_id] <- adt_def.repr());
         record!(self.tables.variant_data[def_id] <- data);
         self.tables.constness.set(def_id.index, hir::Constness::Const);
-        if variant.ctor_kind == CtorKind::Fn {
-            record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
+        if ctor_kind == CtorKind::Fn {
+            record!(self.tables.fn_sig[def_id] <- self.tcx.fn_sig(def_id));
         }
     }
 
@@ -1550,21 +1544,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 let adt_def = self.tcx.adt_def(def_id);
                 record!(self.tables.repr_options[def_id] <- adt_def.repr());
             }
-            hir::ItemKind::Struct(ref struct_def, _) => {
+            hir::ItemKind::Struct(..) => {
                 let adt_def = self.tcx.adt_def(def_id);
                 record!(self.tables.repr_options[def_id] <- adt_def.repr());
                 self.tables.constness.set(def_id.index, hir::Constness::Const);
 
-                // Encode def_ids for each field and method
-                // for methods, write all the stuff get_trait_method
-                // needs to know
-                let ctor = struct_def.ctor_def_id().map(|ctor_def_id| ctor_def_id.local_def_index);
-
                 let variant = adt_def.non_enum_variant();
                 record!(self.tables.variant_data[def_id] <- VariantData {
-                    ctor_kind: variant.ctor_kind,
                     discr: variant.discr,
-                    ctor,
+                    ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)),
                     is_non_exhaustive: variant.is_field_list_non_exhaustive(),
                 });
             }
@@ -1574,9 +1562,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
                 let variant = adt_def.non_enum_variant();
                 record!(self.tables.variant_data[def_id] <- VariantData {
-                    ctor_kind: variant.ctor_kind,
                     discr: variant.discr,
-                    ctor: None,
+                    ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)),
                     is_non_exhaustive: variant.is_field_list_non_exhaustive(),
                 });
             }
@@ -1629,7 +1616,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     for variant in tcx.adt_def(def_id).variants() {
                         yield variant.def_id.index;
                         // Encode constructors which take a separate slot in value namespace.
-                        if let Some(ctor_def_id) = variant.ctor_def_id {
+                        if let Some(ctor_def_id) = variant.ctor_def_id() {
                             yield ctor_def_id.index;
                         }
                     }
@@ -1672,20 +1659,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         match item.kind {
             hir::ItemKind::Enum(..) => {
                 let def = self.tcx.adt_def(item.owner_id.to_def_id());
-                for (i, variant) in def.variants().iter_enumerated() {
+                for (i, _) in def.variants().iter_enumerated() {
                     self.encode_enum_variant_info(def, i);
-
-                    if let Some(_ctor_def_id) = variant.ctor_def_id {
-                        self.encode_enum_variant_ctor(def, i);
-                    }
+                    self.encode_enum_variant_ctor(def, i);
                 }
             }
-            hir::ItemKind::Struct(ref struct_def, _) => {
+            hir::ItemKind::Struct(..) => {
                 let def = self.tcx.adt_def(item.owner_id.to_def_id());
-                // If the struct has a constructor, encode it.
-                if let Some(ctor_def_id) = struct_def.ctor_def_id() {
-                    self.encode_struct_ctor(def, ctor_def_id.to_def_id());
-                }
+                self.encode_struct_ctor(def);
             }
             hir::ItemKind::Impl { .. } => {
                 for &trait_item_def_id in
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index ba6a3aeb209..3e0b5fa6dd9 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -410,10 +410,9 @@ define_tables! {
 
 #[derive(TyEncodable, TyDecodable)]
 struct VariantData {
-    ctor_kind: CtorKind,
     discr: ty::VariantDiscr,
     /// If this is unit or tuple-variant/struct, then this is the index of the ctor id.
-    ctor: Option<DefIndex>,
+    ctor: Option<(CtorKind, DefIndex)>,
     is_non_exhaustive: bool,
 }
 
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index e7c1abd126e..29fe6110797 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -101,10 +101,8 @@ fixed_size_enum! {
         ( Static(ast::Mutability::Mut)             )
         ( Ctor(CtorOf::Struct, CtorKind::Fn)       )
         ( Ctor(CtorOf::Struct, CtorKind::Const)    )
-        ( Ctor(CtorOf::Struct, CtorKind::Fictive)  )
         ( Ctor(CtorOf::Variant, CtorKind::Fn)      )
         ( Ctor(CtorOf::Variant, CtorKind::Const)   )
-        ( Ctor(CtorOf::Variant, CtorKind::Fictive) )
         ( Macro(MacroKind::Bang)                   )
         ( Macro(MacroKind::Attr)                   )
         ( Macro(MacroKind::Derive)                 )
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index e14ea7be9cf..d4456adf201 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -245,15 +245,15 @@ impl<'hir> Map<'hir> {
             },
             Node::Variant(_) => DefKind::Variant,
             Node::Ctor(variant_data) => {
-                // FIXME(eddyb) is this even possible, if we have a `Node::Ctor`?
-                assert_ne!(variant_data.ctor_hir_id(), None);
-
                 let ctor_of = match self.find(self.get_parent_node(hir_id)) {
                     Some(Node::Item(..)) => def::CtorOf::Struct,
                     Some(Node::Variant(..)) => def::CtorOf::Variant,
                     _ => unreachable!(),
                 };
-                DefKind::Ctor(ctor_of, def::CtorKind::from_hir(variant_data))
+                match variant_data.ctor_kind() {
+                    Some(kind) => DefKind::Ctor(ctor_of, kind),
+                    None => bug!("constructor node without a constructor"),
+                }
             }
             Node::AnonConst(_) => {
                 let inline = match self.find(self.get_parent_node(hir_id)) {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 8b70eabb105..364c1b375ae 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2115,10 +2115,10 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                                 .print_def_path(variant_def.def_id, substs)?
                                 .into_buffer();
 
-                            match variant_def.ctor_kind {
-                                CtorKind::Const => fmt.write_str(&name),
-                                CtorKind::Fn => fmt_tuple(fmt, &name),
-                                CtorKind::Fictive => {
+                            match variant_def.ctor_kind() {
+                                Some(CtorKind::Const) => fmt.write_str(&name),
+                                Some(CtorKind::Fn) => fmt_tuple(fmt, &name),
+                                None => {
                                     let mut struct_fmt = fmt.debug_struct(&name);
                                     for (field, place) in iter::zip(&variant_def.fields, places) {
                                         struct_fmt.field(field.name.as_str(), place);
@@ -2955,14 +2955,14 @@ fn pretty_print_const_value<'tcx>(
                             let cx = cx.print_value_path(variant_def.def_id, substs)?;
                             fmt.write_str(&cx.into_buffer())?;
 
-                            match variant_def.ctor_kind {
-                                CtorKind::Const => {}
-                                CtorKind::Fn => {
+                            match variant_def.ctor_kind() {
+                                Some(CtorKind::Const) => {}
+                                Some(CtorKind::Fn) => {
                                     fmt.write_str("(")?;
                                     comma_sep(fmt, fields)?;
                                     fmt.write_str(")")?;
                                 }
-                                CtorKind::Fictive => {
+                                None => {
                                     fmt.write_str(" {{ ")?;
                                     let mut first = true;
                                     for (field_def, field) in iter::zip(&variant_def.fields, fields)
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index ea7a507d7a4..8bef9dfe099 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -10,7 +10,6 @@
 
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir as hir;
-use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::RangeEnd;
 use rustc_index::newtype_index;
@@ -751,7 +750,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
 
                     // Only for Adt we can have `S {...}`,
                     // which we handle separately here.
-                    if variant.ctor_kind == CtorKind::Fictive {
+                    if variant.ctor.is_none() {
                         write!(f, " {{ ")?;
 
                         let mut printed = 0;
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 137b59cf6c2..6b6aa40a160 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -230,7 +230,7 @@ impl AdtDefData {
             AdtKind::Struct => AdtFlags::IS_STRUCT,
         };
 
-        if kind == AdtKind::Struct && variants[VariantIdx::new(0)].ctor_def_id.is_some() {
+        if kind == AdtKind::Struct && variants[VariantIdx::new(0)].ctor.is_some() {
             flags |= AdtFlags::HAS_CTOR;
         }
 
@@ -386,11 +386,9 @@ impl<'tcx> AdtDef<'tcx> {
         //    Baz = 3,
         // }
         // ```
-        if self
-            .variants()
-            .iter()
-            .any(|v| matches!(v.discr, VariantDiscr::Explicit(_)) && v.ctor_kind != CtorKind::Const)
-        {
+        if self.variants().iter().any(|v| {
+            matches!(v.discr, VariantDiscr::Explicit(_)) && v.ctor_kind() != Some(CtorKind::Const)
+        }) {
             return false;
         }
         self.variants().iter().all(|v| v.fields.is_empty())
@@ -405,7 +403,7 @@ impl<'tcx> AdtDef<'tcx> {
     pub fn variant_with_ctor_id(self, cid: DefId) -> &'tcx VariantDef {
         self.variants()
             .iter()
-            .find(|v| v.ctor_def_id == Some(cid))
+            .find(|v| v.ctor_def_id() == Some(cid))
             .expect("variant_with_ctor_id: unknown variant")
     }
 
@@ -422,7 +420,7 @@ impl<'tcx> AdtDef<'tcx> {
     pub fn variant_index_with_ctor_id(self, cid: DefId) -> VariantIdx {
         self.variants()
             .iter_enumerated()
-            .find(|(_, v)| v.ctor_def_id == Some(cid))
+            .find(|(_, v)| v.ctor_def_id() == Some(cid))
             .expect("variant_index_with_ctor_id: unknown variant")
             .0
     }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 8bac76d559f..3f26d337d45 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1812,15 +1812,13 @@ pub struct VariantDef {
     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>,
+    pub ctor: Option<(CtorKind, DefId)>,
     /// Variant or struct name.
     pub name: Symbol,
     /// 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,
 }
@@ -1845,19 +1843,18 @@ impl VariantDef {
     pub fn new(
         name: Symbol,
         variant_did: Option<DefId>,
-        ctor_def_id: Option<DefId>,
+        ctor: Option<(CtorKind, DefId)>,
         discr: VariantDiscr,
         fields: Vec<FieldDef>,
-        ctor_kind: CtorKind,
         adt_kind: AdtKind,
         parent_did: DefId,
         recovered: bool,
         is_field_list_non_exhaustive: bool,
     ) -> Self {
         debug!(
-            "VariantDef::new(name = {:?}, variant_did = {:?}, ctor_def_id = {:?}, discr = {:?},
-             fields = {:?}, ctor_kind = {:?}, adt_kind = {:?}, parent_did = {:?})",
-            name, variant_did, ctor_def_id, discr, fields, ctor_kind, adt_kind, parent_did,
+            "VariantDef::new(name = {:?}, variant_did = {:?}, ctor = {:?}, discr = {:?},
+             fields = {:?}, adt_kind = {:?}, parent_did = {:?})",
+            name, variant_did, ctor, discr, fields, adt_kind, parent_did,
         );
 
         let mut flags = VariantFlags::NO_VARIANT_FLAGS;
@@ -1869,15 +1866,7 @@ impl VariantDef {
             flags |= VariantFlags::IS_RECOVERED;
         }
 
-        VariantDef {
-            def_id: variant_did.unwrap_or(parent_did),
-            ctor_def_id,
-            name,
-            discr,
-            fields,
-            ctor_kind,
-            flags,
-        }
+        VariantDef { def_id: variant_did.unwrap_or(parent_did), ctor, name, discr, fields, flags }
     }
 
     /// Is this field list non-exhaustive?
@@ -1896,6 +1885,16 @@ impl VariantDef {
     pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
         Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
     }
+
+    #[inline]
+    pub fn ctor_kind(&self) -> Option<CtorKind> {
+        self.ctor.map(|(kind, _)| kind)
+    }
+
+    #[inline]
+    pub fn ctor_def_id(&self) -> Option<DefId> {
+        self.ctor.map(|(_, def_id)| def_id)
+    }
 }
 
 impl PartialEq for VariantDef {
@@ -1908,26 +1907,8 @@ impl PartialEq for VariantDef {
         // definition of `VariantDef` changes, a compile-error will be produced,
         // reminding us to revisit this assumption.
 
-        let Self {
-            def_id: lhs_def_id,
-            ctor_def_id: _,
-            name: _,
-            discr: _,
-            fields: _,
-            ctor_kind: _,
-            flags: _,
-        } = &self;
-
-        let Self {
-            def_id: rhs_def_id,
-            ctor_def_id: _,
-            name: _,
-            discr: _,
-            fields: _,
-            ctor_kind: _,
-            flags: _,
-        } = other;
-
+        let Self { def_id: lhs_def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = &self;
+        let Self { def_id: rhs_def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = other;
         lhs_def_id == rhs_def_id
     }
 }
@@ -1944,9 +1925,7 @@ impl Hash for VariantDef {
         // of `VariantDef` changes, a compile-error will be produced, reminding
         // us to revisit this assumption.
 
-        let Self { def_id, ctor_def_id: _, name: _, discr: _, fields: _, ctor_kind: _, flags: _ } =
-            &self;
-
+        let Self { def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = &self;
         def_id.hash(s)
     }
 }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index a0c076cbbb2..d828d08805e 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1487,12 +1487,12 @@ pub trait PrettyPrinter<'tcx>:
                             contents.variant.expect("destructed const of adt without variant idx");
                         let variant_def = &def.variant(variant_idx);
                         p!(print_value_path(variant_def.def_id, substs));
-                        match variant_def.ctor_kind {
-                            CtorKind::Const => {}
-                            CtorKind::Fn => {
+                        match variant_def.ctor_kind() {
+                            Some(CtorKind::Const) => {}
+                            Some(CtorKind::Fn) => {
                                 p!("(", comma_sep(fields), ")");
                             }
-                            CtorKind::Fictive => {
+                            None => {
                                 p!(" {{ ");
                                 let mut first = true;
                                 for (field_def, field) in iter::zip(&variant_def.fields, fields) {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 0df228a0d59..ba04cb6eef8 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -564,7 +564,7 @@ fn check_for_bindings_named_same_as_variants(
             && let ty::Adt(edef, _) = pat_ty.kind()
             && edef.is_enum()
             && edef.variants().iter().any(|variant| {
-                variant.ident(cx.tcx) == ident && variant.ctor_kind == CtorKind::Const
+                variant.ident(cx.tcx) == ident && variant.ctor_kind() == Some(CtorKind::Const)
             })
         {
             let variant_count = edef.variants().len();
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index e7e419c9b42..7ac4fcfa64c 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -747,7 +747,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
 
                 // If this is a tuple or unit struct, define a name
                 // in the value namespace as well.
-                if let Some(ctor_node_id) = vdata.ctor_id() {
+                if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(vdata) {
                     // If the structure is marked as non_exhaustive then lower the visibility
                     // to within the crate.
                     let mut ctor_vis = if vis.is_public()
@@ -773,10 +773,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                         ret_fields.push(field_vis.to_def_id());
                     }
                     let ctor_def_id = self.r.local_def_id(ctor_node_id);
-                    let ctor_res = Res::Def(
-                        DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(vdata)),
-                        ctor_def_id.to_def_id(),
-                    );
+                    let ctor_res =
+                        Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id.to_def_id());
                     self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
                     self.r.visibilities.insert(ctor_def_id, ctor_vis);
 
@@ -999,8 +997,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
             Res::Def(DefKind::Struct, def_id) => {
                 let field_names =
                     cstore.struct_field_names_untracked(def_id, self.r.session).collect();
-                let ctor = cstore.ctor_def_id_and_kind_untracked(def_id);
-                if let Some((ctor_def_id, ctor_kind)) = ctor {
+                if let Some((ctor_kind, ctor_def_id)) = cstore.ctor_untracked(def_id) {
                     let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
                     let ctor_vis = cstore.visibility_untracked(ctor_def_id);
                     let field_visibilities =
@@ -1517,20 +1514,20 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
         };
 
         // 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.data.ctor_id().unwrap_or(variant.id);
-        let ctor_def_id = self.r.local_def_id(ctor_node_id);
-        let ctor_kind = CtorKind::from_ast(&variant.data);
-        let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id.to_def_id());
-        self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
-        if ctor_def_id != def_id {
+        let fields_id = if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&variant.data) {
+            let ctor_def_id = self.r.local_def_id(ctor_node_id);
+            let ctor_res =
+                Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id.to_def_id());
+            self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
             self.r.visibilities.insert(ctor_def_id, ctor_vis);
-        }
+            ctor_def_id
+        } else {
+            def_id
+        };
+
         // Record field names for error reporting.
-        self.insert_field_names_local(ctor_def_id.to_def_id(), &variant.data);
+        // FIXME: Always use non-ctor id as the key.
+        self.insert_field_names_local(fields_id.to_def_id(), &variant.data);
 
         visit::walk_variant(self, variant);
     }
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index b1cee06849d..4bd62d3d824 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -118,8 +118,8 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
                 match i.kind {
                     ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => {
                         // 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, i.span);
+                        if let Some(ctor_node_id) = struct_def.ctor_node_id() {
+                            this.create_def(ctor_node_id, DefPathData::Ctor, i.span);
                         }
                     }
                     _ => {}
@@ -196,8 +196,8 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
         }
         let def = self.create_def(v.id, DefPathData::TypeNs(v.ident.name), v.span);
         self.with_parent(def, |this| {
-            if let Some(ctor_hir_id) = v.data.ctor_id() {
-                this.create_def(ctor_hir_id, DefPathData::Ctor, v.span);
+            if let Some(ctor_node_id) = v.data.ctor_node_id() {
+                this.create_def(ctor_node_id, DefPathData::Ctor, v.span);
             }
             visit::walk_variant(this, v)
         });
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index e0c927dd1e7..b340bee28c3 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1442,13 +1442,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
 
                 err.span_label(span, "constructor is not visible here due to private fields");
             }
-            (
-                Res::Def(
-                    DefKind::Union | DefKind::Variant | DefKind::Ctor(_, CtorKind::Fictive),
-                    def_id,
-                ),
-                _,
-            ) if ns == ValueNS => {
+            (Res::Def(DefKind::Union | DefKind::Variant, def_id), _) if ns == ValueNS => {
                 bad_struct_syntax_suggestion(def_id);
             }
             (Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id), _) if ns == ValueNS => {
@@ -1963,7 +1957,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                 let has_no_fields = self.r.field_names.get(&def_id).map_or(false, |f| f.is_empty());
                 match kind {
                     CtorKind::Const => false,
-                    CtorKind::Fn | CtorKind::Fictive if has_no_fields => false,
+                    CtorKind::Fn if has_no_fields => false,
                     _ => true,
                 }
             };
@@ -1975,7 +1969,6 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                 .map(|(variant, kind)| match kind {
                     CtorKind::Const => variant,
                     CtorKind::Fn => format!("({}())", variant),
-                    CtorKind::Fictive => format!("({} {{}})", variant),
                 })
                 .collect::<Vec<_>>();
             let no_suggestable_variant = suggestable_variants.is_empty();
@@ -2001,7 +1994,6 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
                 .filter_map(|(variant, kind)| match kind {
                     CtorKind::Fn => Some(format!("({}(/* fields */))", variant)),
-                    CtorKind::Fictive => Some(format!("({} {{ /* fields */ }})", variant)),
                     _ => None,
                 })
                 .collect::<Vec<_>>();
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 6ad0a7d2911..d1a2aee207d 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -689,15 +689,15 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
                         self.push("V");
                         self = self.print_def_path(variant_def.def_id, substs)?;
 
-                        match variant_def.ctor_kind {
-                            CtorKind::Const => {
+                        match variant_def.ctor_kind() {
+                            Some(CtorKind::Const) => {
                                 self.push("U");
                             }
-                            CtorKind::Fn => {
+                            Some(CtorKind::Fn) => {
                                 self.push("T");
                                 self = print_field_list(self)?;
                             }
-                            CtorKind::Fictive => {
+                            None => {
                                 self.push("S");
                                 for (field_def, field) in iter::zip(&variant_def.fields, fields) {
                                     // HACK(eddyb) this mimics `path_append`,
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 3fc4aae923a..e7c3e5a45e8 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -276,7 +276,7 @@ fn build_struct(cx: &mut DocContext<'_>, did: DefId) -> clean::Struct {
     let variant = cx.tcx.adt_def(did).non_enum_variant();
 
     clean::Struct {
-        struct_type: variant.ctor_kind,
+        ctor_kind: variant.ctor_kind(),
         generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
         fields: variant.fields.iter().map(|x| clean_middle_field(x, cx)).collect(),
     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c20595614b0..7085bc8d1be 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1842,16 +1842,16 @@ pub(crate) fn clean_field_with_def_id(
 }
 
 pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
-    let kind = match variant.ctor_kind {
-        CtorKind::Const => Variant::CLike(match variant.discr {
+    let kind = match variant.ctor_kind() {
+        Some(CtorKind::Const) => Variant::CLike(match variant.discr {
             ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
             ty::VariantDiscr::Relative(_) => None,
         }),
-        CtorKind::Fn => Variant::Tuple(
+        Some(CtorKind::Fn) => Variant::Tuple(
             variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
         ),
-        CtorKind::Fictive => Variant::Struct(VariantStruct {
-            struct_type: CtorKind::Fictive,
+        None => Variant::Struct(VariantStruct {
+            ctor_kind: None,
             fields: variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
         }),
     };
@@ -1865,7 +1865,7 @@ fn clean_variant_data<'tcx>(
 ) -> Variant {
     match variant {
         hir::VariantData::Struct(..) => Variant::Struct(VariantStruct {
-            struct_type: CtorKind::from_hir(variant),
+            ctor_kind: None,
             fields: variant.fields().iter().map(|x| clean_field(x, cx)).collect(),
         }),
         hir::VariantData::Tuple(..) => {
@@ -2060,7 +2060,7 @@ fn clean_maybe_renamed_item<'tcx>(
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
             ItemKind::Struct(ref variant_data, generics) => StructItem(Struct {
-                struct_type: CtorKind::from_hir(variant_data),
+                ctor_kind: variant_data.ctor_kind(),
                 generics: clean_generics(generics, cx),
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 3d13f7463cb..340d6d7df18 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -2081,7 +2081,7 @@ impl From<hir::PrimTy> for PrimitiveType {
 
 #[derive(Clone, Debug)]
 pub(crate) struct Struct {
-    pub(crate) struct_type: CtorKind,
+    pub(crate) ctor_kind: Option<CtorKind>,
     pub(crate) generics: Generics,
     pub(crate) fields: Vec<Item>,
 }
@@ -2109,7 +2109,7 @@ impl Union {
 /// only as a variant in an enum.
 #[derive(Clone, Debug)]
 pub(crate) struct VariantStruct {
-    pub(crate) struct_type: CtorKind,
+    pub(crate) ctor_kind: Option<CtorKind>,
     pub(crate) fields: Vec<Item>,
 }
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 647eb69d9a6..d12874e1bfd 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -2280,12 +2280,12 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea
     let fields = get_struct_fields_name(&s.fields);
 
     if !fields.is_empty() {
-        match s.struct_type {
-            CtorKind::Fictive => {
+        match s.ctor_kind {
+            None => {
                 print_sidebar_block(&mut sidebar, "fields", "Fields", fields.iter());
             }
-            CtorKind::Fn => print_sidebar_title(&mut sidebar, "fields", "Tuple Fields"),
-            CtorKind::Const => {}
+            Some(CtorKind::Fn) => print_sidebar_title(&mut sidebar, "fields", "Tuple Fields"),
+            Some(CtorKind::Const) => {}
         }
     }
 
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index c95f117a205..a0e5309a70c 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1232,7 +1232,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
                                     w,
                                     v,
                                     None,
-                                    s.struct_type,
+                                    s.ctor_kind,
                                     &s.fields,
                                     "    ",
                                     false,
@@ -1458,7 +1458,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
     wrap_into_item_decl(w, |w| {
         wrap_item(w, "struct", |w| {
             render_attributes_in_code(w, it);
-            render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true, cx);
+            render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
         });
     });
 
@@ -1472,14 +1472,14 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
             _ => None,
         })
         .peekable();
-    if let CtorKind::Fictive | CtorKind::Fn = s.struct_type {
+    if let None | Some(CtorKind::Fn) = s.ctor_kind {
         if fields.peek().is_some() {
             write!(
                 w,
                 "<h2 id=\"fields\" class=\"fields small-section-header\">\
                      {}{}<a href=\"#fields\" class=\"anchor\"></a>\
                  </h2>",
-                if let CtorKind::Fictive = s.struct_type { "Fields" } else { "Tuple Fields" },
+                if s.ctor_kind.is_none() { "Fields" } else { "Tuple Fields" },
                 document_non_exhaustive_header(it)
             );
             document_non_exhaustive(w, it);
@@ -1739,7 +1739,7 @@ fn render_struct(
     w: &mut Buffer,
     it: &clean::Item,
     g: Option<&clean::Generics>,
-    ty: CtorKind,
+    ty: Option<CtorKind>,
     fields: &[clean::Item],
     tab: &str,
     structhead: bool,
@@ -1757,7 +1757,7 @@ fn render_struct(
         write!(w, "{}", g.print(cx))
     }
     match ty {
-        CtorKind::Fictive => {
+        None => {
             let where_diplayed = g.map(|g| print_where_clause_and_check(w, g, cx)).unwrap_or(false);
 
             // If there wasn't a `where` clause, we add a whitespace.
@@ -1799,7 +1799,7 @@ fn render_struct(
             }
             w.write_str("}");
         }
-        CtorKind::Fn => {
+        Some(CtorKind::Fn) => {
             w.write_str("(");
             for (i, field) in fields.iter().enumerate() {
                 if i > 0 {
@@ -1827,7 +1827,7 @@ fn render_struct(
                 w.write_str(";");
             }
         }
-        CtorKind::Const => {
+        Some(CtorKind::Const) => {
             // Needed for PhantomData.
             if let Some(g) = g {
                 write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline));
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 6995778a93d..d7184053c87 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -315,15 +315,15 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
 impl FromWithTcx<clean::Struct> for Struct {
     fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self {
         let fields_stripped = struct_.has_stripped_entries();
-        let clean::Struct { struct_type, generics, fields } = struct_;
+        let clean::Struct { ctor_kind, generics, fields } = struct_;
 
-        let kind = match struct_type {
-            CtorKind::Fn => StructKind::Tuple(ids_keeping_stripped(fields, tcx)),
-            CtorKind::Const => {
+        let kind = match ctor_kind {
+            Some(CtorKind::Fn) => StructKind::Tuple(ids_keeping_stripped(fields, tcx)),
+            Some(CtorKind::Const) => {
                 assert!(fields.is_empty());
                 StructKind::Unit
             }
-            CtorKind::Fictive => StructKind::Plain { fields: ids(fields, tcx), fields_stripped },
+            None => StructKind::Plain { fields: ids(fields, tcx), fields_stripped },
         };
 
         Struct {
diff --git a/src/test/ui/empty/empty-struct-braces-expr.rs b/src/test/ui/empty/empty-struct-braces-expr.rs
index f4144277f16..2aab3e7772c 100644
--- a/src/test/ui/empty/empty-struct-braces-expr.rs
+++ b/src/test/ui/empty/empty-struct-braces-expr.rs
@@ -17,7 +17,7 @@ fn main() {
     //~^ ERROR expected function, tuple struct or tuple variant, found struct `Empty1`
     let e3 = E::Empty3; //~ ERROR expected value, found struct variant `E::Empty3`
     let e3 = E::Empty3();
-    //~^ ERROR expected function, tuple struct or tuple variant, found struct variant `E::Empty3`
+    //~^ ERROR expected value, found struct variant `E::Empty3`
 
     let xe1 = XEmpty1; //~ ERROR expected value, found struct `XEmpty1`
     let xe1 = XEmpty1();
diff --git a/src/test/ui/empty/empty-struct-braces-expr.stderr b/src/test/ui/empty/empty-struct-braces-expr.stderr
index 5b0ca613fc4..e1a7a02a568 100644
--- a/src/test/ui/empty/empty-struct-braces-expr.stderr
+++ b/src/test/ui/empty/empty-struct-braces-expr.stderr
@@ -21,24 +21,6 @@ help: a unit struct with a similar name exists
 LL |     let e1 = XEmpty2;
    |              ~~~~~~~
 
-error[E0423]: expected value, found struct variant `E::Empty3`
-  --> $DIR/empty-struct-braces-expr.rs:18:14
-   |
-LL |     Empty3 {}
-   |     --------- `E::Empty3` defined here
-...
-LL |     let e3 = E::Empty3;
-   |              ^^^^^^^^^ help: use struct literal syntax instead: `E::Empty3 {}`
-
-error[E0423]: expected function, tuple struct or tuple variant, found struct variant `E::Empty3`
-  --> $DIR/empty-struct-braces-expr.rs:19:14
-   |
-LL |     Empty3 {}
-   |     --------- `E::Empty3` defined here
-...
-LL |     let e3 = E::Empty3();
-   |              ^^^^^^^^^^^ help: use struct literal syntax instead: `E::Empty3 {}`
-
 error[E0423]: expected value, found struct `XEmpty1`
   --> $DIR/empty-struct-braces-expr.rs:22:15
    |
@@ -84,6 +66,18 @@ help: a unit struct with a similar name exists
 LL |     let e1 = XEmpty2();
    |              ~~~~~~~
 
+error[E0533]: expected value, found struct variant `E::Empty3`
+  --> $DIR/empty-struct-braces-expr.rs:18:14
+   |
+LL |     let e3 = E::Empty3;
+   |              ^^^^^^^^^ not a value
+
+error[E0533]: expected value, found struct variant `E::Empty3`
+  --> $DIR/empty-struct-braces-expr.rs:19:14
+   |
+LL |     let e3 = E::Empty3();
+   |              ^^^^^^^^^ not a value
+
 error[E0423]: expected function, tuple struct or tuple variant, found struct `XEmpty1`
   --> $DIR/empty-struct-braces-expr.rs:23:15
    |
@@ -132,5 +126,5 @@ LL |     XE::Empty1 {};
 
 error: aborting due to 9 previous errors
 
-Some errors have detailed explanations: E0423, E0599.
+Some errors have detailed explanations: E0423, E0533, E0599.
 For more information about an error, try `rustc --explain E0423`.
diff --git a/src/test/ui/empty/empty-struct-braces-pat-1.stderr b/src/test/ui/empty/empty-struct-braces-pat-1.stderr
index 0215a9e5935..14e09fc27a0 100644
--- a/src/test/ui/empty/empty-struct-braces-pat-1.stderr
+++ b/src/test/ui/empty/empty-struct-braces-pat-1.stderr
@@ -1,34 +1,15 @@
-error[E0532]: expected unit struct, unit variant or constant, found struct variant `E::Empty3`
+error[E0533]: expected unit struct, unit variant or constant, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-pat-1.rs:24:9
    |
-LL |     Empty3 {}
-   |     --------- `E::Empty3` defined here
-...
 LL |         E::Empty3 => ()
-   |         ^^^^^^^^^ help: use struct pattern syntax instead: `E::Empty3 {}`
+   |         ^^^^^^^^^ not a unit struct, unit variant or constant
 
-error[E0532]: expected unit struct, unit variant or constant, found struct variant `XE::XEmpty3`
+error[E0533]: expected unit struct, unit variant or constant, found struct variant `XE::XEmpty3`
   --> $DIR/empty-struct-braces-pat-1.rs:31:9
    |
 LL |         XE::XEmpty3 => ()
-   |         ^^^^^^^^^^^
-   |
-  ::: $DIR/auxiliary/empty-struct.rs:6:5
-   |
-LL |     XEmpty3 {},
-   |     ------- `XE::XEmpty3` defined here
-LL |     XEmpty4,
-   |     ------- similarly named unit variant `XEmpty4` defined here
-   |
-help: use struct pattern syntax instead
-   |
-LL |         XE::XEmpty3 { /* fields */ } => ()
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-help: a unit variant with a similar name exists
-   |
-LL |         XE::XEmpty4 => ()
-   |             ~~~~~~~
+   |         ^^^^^^^^^^^ not a unit struct, unit variant or constant
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0532`.
+For more information about this error, try `rustc --explain E0533`.
diff --git a/src/test/ui/empty/empty-struct-braces-pat-3.stderr b/src/test/ui/empty/empty-struct-braces-pat-3.stderr
index 615e7fb4aae..00c8b12e6f9 100644
--- a/src/test/ui/empty/empty-struct-braces-pat-3.stderr
+++ b/src/test/ui/empty/empty-struct-braces-pat-3.stderr
@@ -1,67 +1,27 @@
-error[E0532]: expected tuple struct or tuple variant, found struct variant `E::Empty3`
+error[E0164]: expected tuple struct or tuple variant, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-pat-3.rs:17:9
    |
-LL |     Empty3 {}
-   |     --------- `E::Empty3` defined here
-...
 LL |         E::Empty3() => ()
-   |         ^^^^^^^^^^^ help: use struct pattern syntax instead: `E::Empty3 {}`
+   |         ^^^^^^^^^^^ not a tuple struct or tuple variant
 
-error[E0532]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3`
+error[E0164]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3`
   --> $DIR/empty-struct-braces-pat-3.rs:21:9
    |
 LL |         XE::XEmpty3() => ()
-   |         ^^^^^^^^^^^^^
-   |
-  ::: $DIR/auxiliary/empty-struct.rs:6:5
-   |
-LL |     XEmpty3 {},
-   |     ------- `XE::XEmpty3` defined here
-LL |     XEmpty4,
-LL |     XEmpty5(),
-   |     ------- similarly named tuple variant `XEmpty5` defined here
-   |
-help: use struct pattern syntax instead
-   |
-LL |         XE::XEmpty3 { /* fields */ } => ()
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-help: a tuple variant with a similar name exists
-   |
-LL |         XE::XEmpty5() => ()
-   |             ~~~~~~~
+   |         ^^^^^^^^^^^^^ not a tuple struct or tuple variant
 
-error[E0532]: expected tuple struct or tuple variant, found struct variant `E::Empty3`
+error[E0164]: expected tuple struct or tuple variant, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-pat-3.rs:25:9
    |
-LL |     Empty3 {}
-   |     --------- `E::Empty3` defined here
-...
 LL |         E::Empty3(..) => ()
-   |         ^^^^^^^^^^^^^ help: use struct pattern syntax instead: `E::Empty3 {}`
+   |         ^^^^^^^^^^^^^ not a tuple struct or tuple variant
 
-error[E0532]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3`
+error[E0164]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3`
   --> $DIR/empty-struct-braces-pat-3.rs:29:9
    |
 LL |         XE::XEmpty3(..) => ()
-   |         ^^^^^^^^^^^^^^^
-   |
-  ::: $DIR/auxiliary/empty-struct.rs:6:5
-   |
-LL |     XEmpty3 {},
-   |     ------- `XE::XEmpty3` defined here
-LL |     XEmpty4,
-LL |     XEmpty5(),
-   |     ------- similarly named tuple variant `XEmpty5` defined here
-   |
-help: use struct pattern syntax instead
-   |
-LL |         XE::XEmpty3 { /* fields */ } => ()
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-help: a tuple variant with a similar name exists
-   |
-LL |         XE::XEmpty5(..) => ()
-   |             ~~~~~~~
+   |         ^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0532`.
+For more information about this error, try `rustc --explain E0164`.
diff --git a/src/test/ui/error-codes/E0164.stderr b/src/test/ui/error-codes/E0164.stderr
index 0db89dfec84..5a80d6ec31a 100644
--- a/src/test/ui/error-codes/E0164.stderr
+++ b/src/test/ui/error-codes/E0164.stderr
@@ -2,7 +2,7 @@ error[E0164]: expected tuple struct or tuple variant, found associated constant
   --> $DIR/E0164.rs:9:9
    |
 LL |         Foo::B(i) => i,
-   |         ^^^^^^^^^ not a tuple variant or struct
+   |         ^^^^^^^^^ not a tuple struct or tuple variant
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-19086.rs b/src/test/ui/issues/issue-19086.rs
index cc83874cb16..42148c5f5a1 100644
--- a/src/test/ui/issues/issue-19086.rs
+++ b/src/test/ui/issues/issue-19086.rs
@@ -8,6 +8,6 @@ fn main() {
     let f = FooB { x: 3, y: 4 };
     match f {
         FooB(a, b) => println!("{} {}", a, b),
-        //~^ ERROR expected tuple struct or tuple variant, found struct variant `FooB`
+        //~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
     }
 }
diff --git a/src/test/ui/issues/issue-19086.stderr b/src/test/ui/issues/issue-19086.stderr
index a54f1008e4b..a3c06a72511 100644
--- a/src/test/ui/issues/issue-19086.stderr
+++ b/src/test/ui/issues/issue-19086.stderr
@@ -1,4 +1,4 @@
-error[E0532]: expected tuple struct or tuple variant, found struct variant `FooB`
+error[E0532]: expected tuple struct or tuple variant, found variant `FooB`
   --> $DIR/issue-19086.rs:10:9
    |
 LL |     FooB { x: i32, y: i32 }
diff --git a/src/test/ui/issues/issue-28992-empty.stderr b/src/test/ui/issues/issue-28992-empty.stderr
index 71f337278f2..f69773b8c2b 100644
--- a/src/test/ui/issues/issue-28992-empty.stderr
+++ b/src/test/ui/issues/issue-28992-empty.stderr
@@ -8,7 +8,7 @@ error[E0164]: expected tuple struct or tuple variant, found associated constant
   --> $DIR/issue-28992-empty.rs:14:12
    |
 LL |     if let S::C2(..) = 0 {}
-   |            ^^^^^^^^^ not a tuple variant or struct
+   |            ^^^^^^^^^ not a tuple struct or tuple variant
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-56835.stderr b/src/test/ui/issues/issue-56835.stderr
index c200ba8d52a..e949ae7b324 100644
--- a/src/test/ui/issues/issue-56835.stderr
+++ b/src/test/ui/issues/issue-56835.stderr
@@ -8,7 +8,7 @@ error[E0164]: expected tuple struct or tuple variant, found self constructor `Se
   --> $DIR/issue-56835.rs:4:12
    |
 LL |     fn bar(Self(foo): Self) {}
-   |            ^^^^^^^^^ not a tuple variant or struct
+   |            ^^^^^^^^^ not a tuple struct or tuple variant
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-63983.stderr b/src/test/ui/issues/issue-63983.stderr
index eb042834102..f90c8111626 100644
--- a/src/test/ui/issues/issue-63983.stderr
+++ b/src/test/ui/issues/issue-63983.stderr
@@ -7,15 +7,13 @@ LL |     Tuple(i32),
 LL |         MyEnum::Tuple => "",
    |         ^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `MyEnum::Tuple(_)`
 
-error[E0532]: expected unit struct, unit variant or constant, found struct variant `MyEnum::Struct`
+error[E0533]: expected unit struct, unit variant or constant, found struct variant `MyEnum::Struct`
   --> $DIR/issue-63983.rs:10:9
    |
-LL |     Struct{ s: i32 },
-   |     ---------------- `MyEnum::Struct` defined here
-...
 LL |         MyEnum::Struct => "",
-   |         ^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `MyEnum::Struct { s }`
+   |         ^^^^^^^^^^^^^^ not a unit struct, unit variant or constant
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0532`.
+Some errors have detailed explanations: E0532, E0533.
+For more information about an error, try `rustc --explain E0532`.
diff --git a/src/test/ui/methods/method-path-in-pattern.stderr b/src/test/ui/methods/method-path-in-pattern.stderr
index 1d1bdb6b052..63c7abe0e4a 100644
--- a/src/test/ui/methods/method-path-in-pattern.stderr
+++ b/src/test/ui/methods/method-path-in-pattern.stderr
@@ -2,37 +2,37 @@ error[E0533]: expected unit struct, unit variant or constant, found associated f
   --> $DIR/method-path-in-pattern.rs:15:9
    |
 LL |         Foo::bar => {}
-   |         ^^^^^^^^
+   |         ^^^^^^^^ not a unit struct, unit variant or constant
 
 error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::bar`
   --> $DIR/method-path-in-pattern.rs:19:9
    |
 LL |         <Foo>::bar => {}
-   |         ^^^^^^^^^^
+   |         ^^^^^^^^^^ not a unit struct, unit variant or constant
 
 error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::trait_bar`
   --> $DIR/method-path-in-pattern.rs:23:9
    |
 LL |         <Foo>::trait_bar => {}
-   |         ^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^ not a unit struct, unit variant or constant
 
 error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::bar`
   --> $DIR/method-path-in-pattern.rs:26:12
    |
 LL |     if let Foo::bar = 0u32 {}
-   |            ^^^^^^^^
+   |            ^^^^^^^^ not a unit struct, unit variant or constant
 
 error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::bar`
   --> $DIR/method-path-in-pattern.rs:28:12
    |
 LL |     if let <Foo>::bar = 0u32 {}
-   |            ^^^^^^^^^^
+   |            ^^^^^^^^^^ not a unit struct, unit variant or constant
 
 error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::trait_bar`
   --> $DIR/method-path-in-pattern.rs:30:12
    |
 LL |     if let Foo::trait_bar = 0u32 {}
-   |            ^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^ not a unit struct, unit variant or constant
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/namespace/namespace-mix.rs b/src/test/ui/namespace/namespace-mix.rs
index b0f7e3c6225..c5b30f148bd 100644
--- a/src/test/ui/namespace/namespace-mix.rs
+++ b/src/test/ui/namespace/namespace-mix.rs
@@ -97,13 +97,13 @@ mod m8 {
 
 fn f78() {
     check(m7::V{}); //~ ERROR c::Item
-    check(m7::V); //~ ERROR expected value, found struct variant `m7::V`
+    check(m7::V); //~ ERROR expected value, found type alias `m7::V`
     check(m8::V{}); //~ ERROR c::E
     check(m8::V); //~ ERROR c::Item
 }
 fn xf78() {
     check(xm7::V{}); //~ ERROR c::Item
-    check(xm7::V); //~ ERROR expected value, found struct variant `xm7::V`
+    check(xm7::V); //~ ERROR expected value, found type alias `xm7::V`
     check(xm8::V{}); //~ ERROR c::E
     check(xm8::V); //~ ERROR c::Item
 }
diff --git a/src/test/ui/namespace/namespace-mix.stderr b/src/test/ui/namespace/namespace-mix.stderr
index c07914df727..cb72d4a1c42 100644
--- a/src/test/ui/namespace/namespace-mix.stderr
+++ b/src/test/ui/namespace/namespace-mix.stderr
@@ -52,21 +52,16 @@ LL -     check(xm1::S);
 LL +     check(S);
    |
 
-error[E0423]: expected value, found struct variant `m7::V`
+error[E0423]: expected value, found type alias `m7::V`
   --> $DIR/namespace-mix.rs:100:11
    |
-LL |         V {},
-   |         ---- `m7::V` defined here
 LL |         TV(),
    |         ---- similarly named tuple variant `TV` defined here
 ...
 LL |     check(m7::V);
    |           ^^^^^
    |
-help: use struct literal syntax instead
-   |
-LL |     check(m7::V {});
-   |           ~~~~~~~~
+   = note: can't use a type alias as a constructor
 help: a tuple variant with a similar name exists
    |
 LL |     check(m7::TV);
@@ -83,23 +78,18 @@ LL -     check(m7::V);
 LL +     check(V);
    |
 
-error[E0423]: expected value, found struct variant `xm7::V`
+error[E0423]: expected value, found type alias `xm7::V`
   --> $DIR/namespace-mix.rs:106:11
    |
 LL |     check(xm7::V);
    |           ^^^^^^
    |
-  ::: $DIR/auxiliary/namespace-mix.rs:6:9
+  ::: $DIR/auxiliary/namespace-mix.rs:7:9
    |
-LL |         V {},
-   |         - `xm7::V` defined here
 LL |         TV(),
    |         -- similarly named tuple variant `TV` defined here
    |
-help: use struct literal syntax instead
-   |
-LL |     check(xm7::V { /* fields */ });
-   |           ~~~~~~~~~~~~~~~~~~~~~~~
+   = note: can't use a type alias as a constructor
 help: a tuple variant with a similar name exists
    |
 LL |     check(xm7::TV);
diff --git a/src/test/ui/parser/recover-from-bad-variant.stderr b/src/test/ui/parser/recover-from-bad-variant.stderr
index 483312c16cc..04968bbdf99 100644
--- a/src/test/ui/parser/recover-from-bad-variant.stderr
+++ b/src/test/ui/parser/recover-from-bad-variant.stderr
@@ -14,14 +14,11 @@ LL -     let x = Enum::Foo(a: 3, b: 4);
 LL +     let x = Enum::Foo(3, 4);
    |
 
-error[E0532]: expected tuple struct or tuple variant, found struct variant `Enum::Foo`
+error[E0164]: expected tuple struct or tuple variant, found struct variant `Enum::Foo`
   --> $DIR/recover-from-bad-variant.rs:10:9
    |
-LL |     Foo { a: usize, b: usize },
-   |     -------------------------- `Enum::Foo` defined here
-...
 LL |         Enum::Foo(a, b) => {}
-   |         ^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `Enum::Foo { a, b }`
+   |         ^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
 
 error[E0769]: tuple variant `Enum::Bar` written as struct variant
   --> $DIR/recover-from-bad-variant.rs:12:9
@@ -36,5 +33,5 @@ LL |         Enum::Bar(a, b) => {}
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0532, E0769.
-For more information about an error, try `rustc --explain E0532`.
+Some errors have detailed explanations: E0164, E0769.
+For more information about an error, try `rustc --explain E0164`.
diff --git a/src/test/ui/parser/struct-literal-variant-in-if.stderr b/src/test/ui/parser/struct-literal-variant-in-if.stderr
index 4cffbe433b8..9f0c0074d67 100644
--- a/src/test/ui/parser/struct-literal-variant-in-if.stderr
+++ b/src/test/ui/parser/struct-literal-variant-in-if.stderr
@@ -42,16 +42,11 @@ help: surround the struct literal with parentheses
 LL |     if x == (E::K { field: "" }) {}
    |             +                  +
 
-error[E0423]: expected value, found struct variant `E::V`
+error[E0533]: expected value, found struct variant `E::V`
   --> $DIR/struct-literal-variant-in-if.rs:10:13
    |
 LL |     if x == E::V { field } {}
    |             ^^^^ not a value
-   |
-help: surround the struct literal with parentheses
-   |
-LL |     if x == (E::V { field }) {}
-   |             +              +
 
 error[E0308]: mismatched types
   --> $DIR/struct-literal-variant-in-if.rs:10:20
@@ -72,5 +67,5 @@ LL |     let y: usize = ();
 
 error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0308, E0423.
+Some errors have detailed explanations: E0308, E0533.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/pattern/pattern-binding-disambiguation.rs b/src/test/ui/pattern/pattern-binding-disambiguation.rs
index 2e80ea345dc..ce1d8c6c047 100644
--- a/src/test/ui/pattern/pattern-binding-disambiguation.rs
+++ b/src/test/ui/pattern/pattern-binding-disambiguation.rs
@@ -33,7 +33,7 @@ fn main() {
         TupleVariant => {} //~ ERROR match bindings cannot shadow tuple variants
     }
     match doesnt_matter {
-        BracedVariant => {} //~ ERROR match bindings cannot shadow struct variants
+        BracedVariant => {} // OK, `BracedVariant` is a fresh binding
     }
     match CONST {
         CONST => {} // OK, `CONST` is a const pattern
@@ -50,7 +50,7 @@ fn main() {
     let BracedStruct = doesnt_matter; // OK, `BracedStruct` is a fresh binding
     let UnitVariant = UnitVariant; // OK, `UnitVariant` is a unit variant pattern
     let TupleVariant = doesnt_matter; //~ ERROR let bindings cannot shadow tuple variants
-    let BracedVariant = doesnt_matter; //~ ERROR let bindings cannot shadow struct variants
+    let BracedVariant = doesnt_matter; // OK, `BracedVariant` is a fresh binding
     let CONST = CONST; // OK, `CONST` is a const pattern
     let STATIC = doesnt_matter; //~ ERROR let bindings cannot shadow statics
     let function = doesnt_matter; // OK, `function` is a fresh binding
diff --git a/src/test/ui/pattern/pattern-binding-disambiguation.stderr b/src/test/ui/pattern/pattern-binding-disambiguation.stderr
index 1529e538b55..d54467b3c0c 100644
--- a/src/test/ui/pattern/pattern-binding-disambiguation.stderr
+++ b/src/test/ui/pattern/pattern-binding-disambiguation.stderr
@@ -22,15 +22,6 @@ LL |         TupleVariant => {}
    |         cannot be named the same as a tuple variant
    |         help: try specify the pattern arguments: `TupleVariant(..)`
 
-error[E0530]: match bindings cannot shadow struct variants
-  --> $DIR/pattern-binding-disambiguation.rs:36:9
-   |
-LL | use E::*;
-   |     ---- the struct variant `BracedVariant` is imported here
-...
-LL |         BracedVariant => {}
-   |         ^^^^^^^^^^^^^ cannot be named the same as a struct variant
-
 error[E0530]: match bindings cannot shadow statics
   --> $DIR/pattern-binding-disambiguation.rs:42:9
    |
@@ -58,15 +49,6 @@ LL | use E::*;
 LL |     let TupleVariant = doesnt_matter;
    |         ^^^^^^^^^^^^ cannot be named the same as a tuple variant
 
-error[E0530]: let bindings cannot shadow struct variants
-  --> $DIR/pattern-binding-disambiguation.rs:53:9
-   |
-LL | use E::*;
-   |     ---- the struct variant `BracedVariant` is imported here
-...
-LL |     let BracedVariant = doesnt_matter;
-   |         ^^^^^^^^^^^^^ cannot be named the same as a struct variant
-
 error[E0530]: let bindings cannot shadow statics
   --> $DIR/pattern-binding-disambiguation.rs:55:9
    |
@@ -76,6 +58,6 @@ LL | static STATIC: () = ();
 LL |     let STATIC = doesnt_matter;
    |         ^^^^^^ cannot be named the same as a static
 
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0530`.
diff --git a/src/test/ui/qualified/qualified-path-params.stderr b/src/test/ui/qualified/qualified-path-params.stderr
index 82cc6e19f9d..a49ed6c8f60 100644
--- a/src/test/ui/qualified/qualified-path-params.stderr
+++ b/src/test/ui/qualified/qualified-path-params.stderr
@@ -2,7 +2,7 @@ error[E0533]: expected unit struct, unit variant or constant, found associated f
   --> $DIR/qualified-path-params.rs:20:9
    |
 LL |         <S as Tr>::A::f::<u8> => {}
-   |         ^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^ not a unit struct, unit variant or constant
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/qualified-path-params.rs:22:15
diff --git a/src/test/ui/resolve/issue-18252.rs b/src/test/ui/resolve/issue-18252.rs
index af0a3cbcb2d..f6ebe292076 100644
--- a/src/test/ui/resolve/issue-18252.rs
+++ b/src/test/ui/resolve/issue-18252.rs
@@ -4,5 +4,5 @@ enum Foo {
 
 fn main() {
     let f = Foo::Variant(42);
-    //~^ ERROR expected function, tuple struct or tuple variant, found struct variant `Foo::Variant`
+    //~^ ERROR expected value, found struct variant `Foo::Variant`
 }
diff --git a/src/test/ui/resolve/issue-18252.stderr b/src/test/ui/resolve/issue-18252.stderr
index 13e7a59732d..d9006c0a6c2 100644
--- a/src/test/ui/resolve/issue-18252.stderr
+++ b/src/test/ui/resolve/issue-18252.stderr
@@ -1,12 +1,9 @@
-error[E0423]: expected function, tuple struct or tuple variant, found struct variant `Foo::Variant`
+error[E0533]: expected value, found struct variant `Foo::Variant`
   --> $DIR/issue-18252.rs:6:13
    |
-LL |     Variant { x: usize }
-   |     -------------------- `Foo::Variant` defined here
-...
 LL |     let f = Foo::Variant(42);
-   |             ^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `Foo::Variant { x: val }`
+   |             ^^^^^^^^^^^^ not a value
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0423`.
+For more information about this error, try `rustc --explain E0533`.
diff --git a/src/test/ui/resolve/issue-19452.stderr b/src/test/ui/resolve/issue-19452.stderr
index 8df84067e67..eff89241fd2 100644
--- a/src/test/ui/resolve/issue-19452.stderr
+++ b/src/test/ui/resolve/issue-19452.stderr
@@ -1,23 +1,15 @@
-error[E0423]: expected value, found struct variant `Homura::Madoka`
+error[E0533]: expected value, found struct variant `Homura::Madoka`
   --> $DIR/issue-19452.rs:10:18
    |
-LL |     Madoka { age: u32 }
-   |     ------------------- `Homura::Madoka` defined here
-...
 LL |     let homura = Homura::Madoka;
-   |                  ^^^^^^^^^^^^^^ help: use struct literal syntax instead: `Homura::Madoka { age: val }`
+   |                  ^^^^^^^^^^^^^^ not a value
 
-error[E0423]: expected value, found struct variant `issue_19452_aux::Homura::Madoka`
+error[E0533]: expected value, found struct variant `issue_19452_aux::Homura::Madoka`
   --> $DIR/issue-19452.rs:13:18
    |
 LL |     let homura = issue_19452_aux::Homura::Madoka;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `issue_19452_aux::Homura::Madoka { /* fields */ }`
-   |
-  ::: $DIR/auxiliary/issue-19452-aux.rs:2:5
-   |
-LL |     Madoka { age: u32 }
-   |     ------ `issue_19452_aux::Homura::Madoka` defined here
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a value
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0423`.
+For more information about this error, try `rustc --explain E0533`.
diff --git a/src/test/ui/resolve/issue-73427.stderr b/src/test/ui/resolve/issue-73427.stderr
index d31c5e47775..4af5f29d809 100644
--- a/src/test/ui/resolve/issue-73427.stderr
+++ b/src/test/ui/resolve/issue-73427.stderr
@@ -17,16 +17,12 @@ LL | | }
    | |_^
 help: you might have meant to use one of the following enum variants
    |
-LL |     (A::Struct {}).foo();
-   |     ~~~~~~~~~~~~~~
 LL |     (A::Tuple()).foo();
    |     ~~~~~~~~~~~~
 LL |     A::Unit.foo();
    |     ~~~~~~~
-help: alternatively, the following enum variants are also available
+help: alternatively, the following enum variant is available
    |
-LL |     (A::StructWithFields { /* fields */ }).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL |     (A::TupleWithFields(/* fields */)).foo();
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -34,7 +30,7 @@ error[E0423]: expected value, found enum `B`
   --> $DIR/issue-73427.rs:35:5
    |
 LL |     B.foo();
-   |     ^
+   |     ^ help: the following enum variant is available: `(B::TupleWithFields(/* fields */))`
    |
 note: the enum is defined here
   --> $DIR/issue-73427.rs:9:1
@@ -44,12 +40,6 @@ LL | |     StructWithFields { x: () },
 LL | |     TupleWithFields(()),
 LL | | }
    | |_^
-help: the following enum variants are available
-   |
-LL |     (B::StructWithFields { /* fields */ }).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     (B::TupleWithFields(/* fields */)).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0423]: expected value, found enum `C`
   --> $DIR/issue-73427.rs:37:5
@@ -70,10 +60,8 @@ help: you might have meant to use the following enum variant
    |
 LL |     C::Unit.foo();
    |     ~~~~~~~
-help: alternatively, the following enum variants are also available
+help: alternatively, the following enum variant is available
    |
-LL |     (C::StructWithFields { /* fields */ }).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL |     (C::TupleWithFields(/* fields */)).foo();
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -130,7 +118,7 @@ error[E0532]: expected tuple struct or tuple variant, found enum `A`
 LL |     if let A(3) = x { }
    |            ^
    |
-   = help: you might have meant to match against one of the enum's non-tuple variants
+   = help: you might have meant to match against the enum's non-tuple variant
 note: the enum is defined here
   --> $DIR/issue-73427.rs:1:1
    |
@@ -155,7 +143,7 @@ error[E0423]: expected function, tuple struct or tuple variant, found enum `A`
 LL |     let x = A(3);
    |             ^
    |
-   = help: you might have meant to construct one of the enum's non-tuple variants
+   = help: you might have meant to construct the enum's non-tuple variant
 note: the enum is defined here
   --> $DIR/issue-73427.rs:1:1
    |
diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr
index 82a4211f08a..d734fa76b4a 100644
--- a/src/test/ui/resolve/privacy-enum-ctor.stderr
+++ b/src/test/ui/resolve/privacy-enum-ctor.stderr
@@ -19,12 +19,10 @@ help: you might have meant to use the following enum variant
    |
 LL |         m::Z::Unit;
    |         ~~~~~~~~~~
-help: alternatively, the following enum variants are also available
+help: alternatively, the following enum variant is available
    |
 LL |         (m::Z::Fn(/* fields */));
    |         ~~~~~~~~~~~~~~~~~~~~~~~~
-LL |         (m::Z::Struct { /* fields */ });
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0423]: expected value, found enum `Z`
   --> $DIR/privacy-enum-ctor.rs:25:9
@@ -47,23 +45,10 @@ help: you might have meant to use the following enum variant
    |
 LL |         m::Z::Unit;
    |         ~~~~~~~~~~
-help: alternatively, the following enum variants are also available
+help: alternatively, the following enum variant is available
    |
 LL |         (m::Z::Fn(/* fields */));
    |         ~~~~~~~~~~~~~~~~~~~~~~~~
-LL |         (m::Z::Struct { /* fields */ });
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error[E0423]: expected value, found struct variant `Z::Struct`
-  --> $DIR/privacy-enum-ctor.rs:29:20
-   |
-LL | /             Struct {
-LL | |                 s: u8,
-LL | |             },
-   | |_____________- `Z::Struct` defined here
-...
-LL |           let _: Z = Z::Struct;
-   |                      ^^^^^^^^^ help: use struct literal syntax instead: `Z::Struct { s: val }`
 
 error[E0423]: expected value, found enum `m::E`
   --> $DIR/privacy-enum-ctor.rs:41:16
@@ -89,12 +74,10 @@ help: you might have meant to use the following enum variant
    |
 LL |     let _: E = E::Unit;
    |                ~~~~~~~
-help: alternatively, the following enum variants are also available
+help: alternatively, the following enum variant is available
    |
 LL |     let _: E = (E::Fn(/* fields */));
    |                ~~~~~~~~~~~~~~~~~~~~~
-LL |     let _: E = (E::Struct { /* fields */ });
-   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 help: a function with a similar name exists
    |
 LL |     let _: E = m::f;
@@ -111,17 +94,6 @@ LL -     let _: E = m::E;
 LL +     let _: E = E;
    |
 
-error[E0423]: expected value, found struct variant `m::E::Struct`
-  --> $DIR/privacy-enum-ctor.rs:45:16
-   |
-LL | /         Struct {
-LL | |             s: u8,
-LL | |         },
-   | |_________- `m::E::Struct` defined here
-...
-LL |       let _: E = m::E::Struct;
-   |                  ^^^^^^^^^^^^ help: use struct literal syntax instead: `m::E::Struct { s: val }`
-
 error[E0423]: expected value, found enum `E`
   --> $DIR/privacy-enum-ctor.rs:49:16
    |
@@ -143,12 +115,10 @@ help: you might have meant to use the following enum variant
    |
 LL |     let _: E = E::Unit;
    |                ~~~~~~~
-help: alternatively, the following enum variants are also available
+help: alternatively, the following enum variant is available
    |
 LL |     let _: E = (E::Fn(/* fields */));
    |                ~~~~~~~~~~~~~~~~~~~~~
-LL |     let _: E = (E::Struct { /* fields */ });
-   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 help: consider importing one of these items instead
    |
 LL | use std::f32::consts::E;
@@ -156,17 +126,6 @@ LL | use std::f32::consts::E;
 LL | use std::f64::consts::E;
    |
 
-error[E0423]: expected value, found struct variant `E::Struct`
-  --> $DIR/privacy-enum-ctor.rs:53:16
-   |
-LL | /         Struct {
-LL | |             s: u8,
-LL | |         },
-   | |_________- `E::Struct` defined here
-...
-LL |       let _: E = E::Struct;
-   |                  ^^^^^^^^^ help: use struct literal syntax instead: `E::Struct { s: val }`
-
 error[E0412]: cannot find type `Z` in this scope
   --> $DIR/privacy-enum-ctor.rs:57:12
    |
@@ -203,12 +162,10 @@ help: you might have meant to use the following enum variant
    |
 LL |     let _: Z = m::Z::Unit;
    |                ~~~~~~~~~~
-help: alternatively, the following enum variants are also available
+help: alternatively, the following enum variant is available
    |
 LL |     let _: Z = (m::Z::Fn(/* fields */));
    |                ~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     let _: Z = (m::Z::Struct { /* fields */ });
-   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0412]: cannot find type `Z` in this scope
   --> $DIR/privacy-enum-ctor.rs:61:12
@@ -240,17 +197,6 @@ note: enum `m::Z` exists but is inaccessible
 LL |         pub(in m) enum Z {
    |         ^^^^^^^^^^^^^^^^ not accessible
 
-error[E0423]: expected value, found struct variant `m::n::Z::Struct`
-  --> $DIR/privacy-enum-ctor.rs:64:16
-   |
-LL | /             Struct {
-LL | |                 s: u8,
-LL | |             },
-   | |_____________- `m::n::Z::Struct` defined here
-...
-LL |       let _: Z = m::n::Z::Struct;
-   |                  ^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `m::n::Z::Struct { s: val }`
-
 error[E0412]: cannot find type `Z` in this scope
   --> $DIR/privacy-enum-ctor.rs:68:12
    |
@@ -332,6 +278,12 @@ help: use parentheses to construct this tuple variant
 LL |         let _: Z = Z::Fn(/* u8 */);
    |                         ++++++++++
 
+error[E0533]: expected value, found struct variant `Z::Struct`
+  --> $DIR/privacy-enum-ctor.rs:29:20
+   |
+LL |         let _: Z = Z::Struct;
+   |                    ^^^^^^^^^ not a value
+
 error[E0618]: expected function, found enum variant `Z::Unit`
   --> $DIR/privacy-enum-ctor.rs:31:17
    |
@@ -367,6 +319,12 @@ help: use parentheses to construct this tuple variant
 LL |     let _: E = m::E::Fn(/* u8 */);
    |                        ++++++++++
 
+error[E0533]: expected value, found struct variant `m::E::Struct`
+  --> $DIR/privacy-enum-ctor.rs:45:16
+   |
+LL |     let _: E = m::E::Struct;
+   |                ^^^^^^^^^^^^ not a value
+
 error[E0618]: expected function, found enum variant `m::E::Unit`
   --> $DIR/privacy-enum-ctor.rs:47:16
    |
@@ -402,6 +360,12 @@ help: use parentheses to construct this tuple variant
 LL |     let _: E = E::Fn(/* u8 */);
    |                     ++++++++++
 
+error[E0533]: expected value, found struct variant `E::Struct`
+  --> $DIR/privacy-enum-ctor.rs:53:16
+   |
+LL |     let _: E = E::Struct;
+   |                ^^^^^^^^^ not a value
+
 error[E0618]: expected function, found enum variant `E::Unit`
   --> $DIR/privacy-enum-ctor.rs:55:16
    |
@@ -419,7 +383,13 @@ LL -     let _: E = E::Unit();
 LL +     let _: E = E::Unit;
    |
 
+error[E0533]: expected value, found struct variant `m::n::Z::Struct`
+  --> $DIR/privacy-enum-ctor.rs:64:16
+   |
+LL |     let _: Z = m::n::Z::Struct;
+   |                ^^^^^^^^^^^^^^^ not a value
+
 error: aborting due to 23 previous errors
 
-Some errors have detailed explanations: E0308, E0412, E0423, E0603, E0618.
+Some errors have detailed explanations: E0308, E0412, E0423, E0533, E0603, E0618.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
index 597dc61c3f7..d0ddb34d9fe 100644
--- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
+++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
@@ -1,23 +1,3 @@
-error[E0423]: expected value, found struct variant `E::B`
-  --> $DIR/fn-or-tuple-struct-without-args.rs:36:16
-   |
-LL |     A(usize),
-   |     -------- similarly named tuple variant `A` defined here
-LL |     B { a: usize },
-   |     -------------- `E::B` defined here
-...
-LL |     let _: E = E::B;
-   |                ^^^^
-   |
-help: use struct literal syntax instead
-   |
-LL |     let _: E = E::B { a: val };
-   |                ~~~~~~~~~~~~~~~
-help: a tuple variant with a similar name exists
-   |
-LL |     let _: E = E::A;
-   |                   ~
-
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:29:20
    |
@@ -144,6 +124,12 @@ help: use parentheses to construct this tuple variant
 LL |     let _: E = E::A(/* usize */);
    |                    +++++++++++++
 
+error[E0533]: expected value, found struct variant `E::B`
+  --> $DIR/fn-or-tuple-struct-without-args.rs:36:16
+   |
+LL |     let _: E = E::B;
+   |                ^^^^ not a value
+
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:37:20
    |
@@ -293,5 +279,5 @@ LL |     let _: usize = closure();
 
 error: aborting due to 17 previous errors
 
-Some errors have detailed explanations: E0308, E0423, E0615.
+Some errors have detailed explanations: E0308, E0533, E0615.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/issue-84700.stderr b/src/test/ui/suggestions/issue-84700.stderr
index b36d8aba36d..ac9f5ab0b0c 100644
--- a/src/test/ui/suggestions/issue-84700.stderr
+++ b/src/test/ui/suggestions/issue-84700.stderr
@@ -7,15 +7,13 @@ LL |     Cow,
 LL |         FarmAnimal::Cow(_) => "moo".to_string(),
    |         ^^^^^^^^^^^^^^^^^^ help: use this syntax instead: `FarmAnimal::Cow`
 
-error[E0532]: expected tuple struct or tuple variant, found struct variant `FarmAnimal::Chicken`
+error[E0164]: expected tuple struct or tuple variant, found struct variant `FarmAnimal::Chicken`
   --> $DIR/issue-84700.rs:17:9
    |
-LL |     Chicken { num_eggs: usize },
-   |     --------------------------- `FarmAnimal::Chicken` defined here
-...
 LL |         FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(),
-   |         ^^^^^^^^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `FarmAnimal::Chicken { num_eggs }`
+   |         ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0532`.
+Some errors have detailed explanations: E0164, E0532.
+For more information about an error, try `rustc --explain E0164`.
diff --git a/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-Self-issue-58006.stderr b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-Self-issue-58006.stderr
index 15d15f2f40d..6870b9d7d09 100644
--- a/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-Self-issue-58006.stderr
+++ b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-Self-issue-58006.stderr
@@ -2,7 +2,7 @@ error[E0533]: expected unit struct, unit variant or constant, found tuple varian
   --> $DIR/incorrect-variant-form-through-Self-issue-58006.rs:8:13
    |
 LL |             Self::A => (),
-   |             ^^^^^^^
+   |             ^^^^^^^ not a unit struct, unit variant or constant
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.rs b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.rs
index e4abb96b4bf..5ed7988e4da 100644
--- a/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.rs
+++ b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.rs
@@ -6,7 +6,7 @@ type Alias = Enum;
 
 fn main() {
     Alias::Braced;
-    //~^ ERROR expected unit struct, unit variant or constant, found struct variant `Alias::Braced` [E0533]
+    //~^ ERROR expected value, found struct variant `Alias::Braced` [E0533]
     let Alias::Braced = panic!();
     //~^ ERROR expected unit struct, unit variant or constant, found struct variant `Alias::Braced` [E0533]
     let Alias::Braced(..) = panic!();
diff --git a/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr
index 8f3180a8639..c9ac99ede6f 100644
--- a/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr
+++ b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr
@@ -1,20 +1,20 @@
-error[E0533]: expected unit struct, unit variant or constant, found struct variant `Alias::Braced`
+error[E0533]: expected value, found struct variant `Alias::Braced`
   --> $DIR/incorrect-variant-form-through-alias-caught.rs:8:5
    |
 LL |     Alias::Braced;
-   |     ^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^ not a value
 
 error[E0533]: expected unit struct, unit variant or constant, found struct variant `Alias::Braced`
   --> $DIR/incorrect-variant-form-through-alias-caught.rs:10:9
    |
 LL |     let Alias::Braced = panic!();
-   |         ^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^ not a unit struct, unit variant or constant
 
 error[E0164]: expected tuple struct or tuple variant, found struct variant `Alias::Braced`
   --> $DIR/incorrect-variant-form-through-alias-caught.rs:12:9
    |
 LL |     let Alias::Braced(..) = panic!();
-   |         ^^^^^^^^^^^^^^^^^ not a tuple variant or struct
+   |         ^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
 
 error[E0618]: expected function, found enum variant `Alias::Unit`
   --> $DIR/incorrect-variant-form-through-alias-caught.rs:15:5
@@ -37,7 +37,7 @@ error[E0164]: expected tuple struct or tuple variant, found unit variant `Alias:
   --> $DIR/incorrect-variant-form-through-alias-caught.rs:17:9
    |
 LL |     let Alias::Unit() = panic!();
-   |         ^^^^^^^^^^^^^ not a tuple variant or struct
+   |         ^^^^^^^^^^^^^ not a tuple struct or tuple variant
 
 error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 6f8d766aef7..7f8d124838c 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -65,14 +65,14 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
                         _ => return,
                     };
                     if arm.guard.is_none() {
-                        missing_variants.retain(|e| e.ctor_def_id != Some(id));
+                        missing_variants.retain(|e| e.ctor_def_id() != Some(id));
                     }
                     path
                 },
                 PatKind::TupleStruct(path, patterns, ..) => {
                     if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
                         if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p)) {
-                            missing_variants.retain(|e| e.ctor_def_id != Some(id));
+                            missing_variants.retain(|e| e.ctor_def_id() != Some(id));
                         }
                     }
                     path
@@ -122,11 +122,11 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
                 s
             },
             variant.name,
-            match variant.ctor_kind {
-                CtorKind::Fn if variant.fields.len() == 1 => "(_)",
-                CtorKind::Fn => "(..)",
-                CtorKind::Const => "",
-                CtorKind::Fictive => "{ .. }",
+            match variant.ctor_kind() {
+                Some(CtorKind::Fn) if variant.fields.len() == 1 => "(_)",
+                Some(CtorKind::Fn) => "(..)",
+                Some(CtorKind::Const) => "",
+                None => "{ .. }",
             }
         )
     };
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
index cfba7fa8791..f2276395fed 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -133,11 +133,11 @@ impl UnnecessaryDefPath {
                 let has_ctor = match cx.tcx.def_kind(def_id) {
                     DefKind::Struct => {
                         let variant = cx.tcx.adt_def(def_id).non_enum_variant();
-                        variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
+                        variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
                     },
                     DefKind::Variant => {
                         let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id);
-                        variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
+                        variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
                     },
                     _ => false,
                 };