about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-03-30 07:51:34 +0100
committerGitHub <noreply@github.com>2019-03-30 07:51:34 +0100
commitd050a157a83d3957a2b0ca96c24a1f61809348a8 (patch)
tree621b5a76f9bf952cea0a380d94f0eda213b0cef2
parent709b72e7a73cbb798b728fd84c384bd0ad8ebf6c (diff)
parent49a6da2cda1a208838911e296fc72a6791e68406 (diff)
downloadrust-d050a157a83d3957a2b0ca96c24a1f61809348a8.tar.gz
rust-d050a157a83d3957a2b0ca96c24a1f61809348a8.zip
Rollup merge of #59376 - davidtwco:finally-rfc-2008-variants, r=petrochenkov,QuietMisdreavus
RFC 2008: Enum Variants

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

r? @petrochenkov
cc @nikomatsakis
-rw-r--r--src/doc/unstable-book/src/language-features/non-exhaustive.md11
-rw-r--r--src/librustc/ty/mod.rs14
-rw-r--r--src/librustc_metadata/encoder.rs9
-rw-r--r--src/librustc_passes/ast_validation.rs9
-rw-r--r--src/librustc_privacy/lib.rs21
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs10
-rw-r--r--src/librustc_typeck/diagnostics.rs13
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/librustdoc/html/render.rs15
-rw-r--r--src/librustdoc/html/static/main.js5
-rw-r--r--src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs10
-rw-r--r--src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs14
-rw-r--r--src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs9
-rw-r--r--src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs53
-rw-r--r--src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs20
-rw-r--r--src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs22
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum.rs44
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs (renamed from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs)1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/struct.rs (renamed from src/test/ui/rfc-2008-non-exhaustive/structs.rs)12
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/struct.stderr (renamed from src/test/ui/rfc-2008-non-exhaustive/structs.stderr)18
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs (renamed from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs)1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/variant.rs (renamed from src/test/ui/rfc-2008-non-exhaustive/variants.rs)25
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/variant.stderr52
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/variants_create.rs17
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr20
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs (renamed from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs)7
26 files changed, 219 insertions, 216 deletions
diff --git a/src/doc/unstable-book/src/language-features/non-exhaustive.md b/src/doc/unstable-book/src/language-features/non-exhaustive.md
index f9840e1b83f..907147c17ef 100644
--- a/src/doc/unstable-book/src/language-features/non-exhaustive.md
+++ b/src/doc/unstable-book/src/language-features/non-exhaustive.md
@@ -7,10 +7,12 @@ The tracking issue for this feature is: [#44109]
 ------------------------
 
 The `non_exhaustive` gate allows you to use the `#[non_exhaustive]` attribute
-on structs and enums. When applied within a crate, users of the crate will need
-to use the `_` pattern when matching enums and use the `..` pattern when
-matching structs. Structs marked as `non_exhaustive` will not be able to be
-created normally outside of the defining crate. This is demonstrated below:
+on structs, enums and enum variants. When applied within a crate, users of the
+crate will need to use the `_` pattern when matching enums and use the `..`
+pattern when matching structs. Enum variants cannot be matched against.
+Structs and enum variants marked as `non_exhaustive` will not be able to
+be created normally outside of the defining crate. This is demonstrated
+below:
 
 ```rust,ignore (pseudo-Rust)
 use std::error::Error as StdError;
@@ -72,4 +74,3 @@ let config = Config { window_width: 640, window_height: 480 };
 // when marked non_exhaustive.
 let &Config { window_width, window_height, .. } = config;
 ```
-
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index f0045136f41..102057c1380 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1869,6 +1869,11 @@ impl<'a, 'gcx, 'tcx> VariantDef {
         if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, "non_exhaustive") {
             debug!("found non-exhaustive field list for {:?}", parent_did);
             flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
+        } else if let Some(variant_did) = variant_did {
+            if tcx.has_attr(variant_did, "non_exhaustive") {
+                debug!("found non-exhaustive field list for {:?}", variant_did);
+                flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
+            }
         }
 
         VariantDef {
@@ -2146,6 +2151,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
             debug!("found non-exhaustive variant list for {:?}", did);
             flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
         }
+
         flags |= match kind {
             AdtKind::Enum => AdtFlags::IS_ENUM,
             AdtKind::Union => AdtFlags::IS_UNION,
@@ -2299,21 +2305,25 @@ impl<'a, 'gcx, 'tcx> AdtDef {
             self.variants.iter().all(|v| v.fields.is_empty())
     }
 
+    /// Return a `VariantDef` given a variant id.
     pub fn variant_with_id(&self, vid: DefId) -> &VariantDef {
         self.variants.iter().find(|v| v.def_id == vid)
             .expect("variant_with_id: unknown variant")
     }
 
+    /// Return a `VariantDef` given a constructor id.
     pub fn variant_with_ctor_id(&self, cid: DefId) -> &VariantDef {
         self.variants.iter().find(|v| v.ctor_def_id == Some(cid))
             .expect("variant_with_ctor_id: unknown variant")
     }
 
+    /// Return the index of `VariantDef` given a variant id.
     pub fn variant_index_with_id(&self, vid: DefId) -> VariantIdx {
         self.variants.iter_enumerated().find(|(_, v)| v.def_id == vid)
             .expect("variant_index_with_id: unknown variant").0
     }
 
+    /// Return the index of `VariantDef` given a constructor id.
     pub fn variant_index_with_ctor_id(&self, cid: DefId) -> VariantIdx {
         self.variants.iter_enumerated().find(|(_, v)| v.ctor_def_id == Some(cid))
             .expect("variant_index_with_ctor_id: unknown variant").0
@@ -2930,8 +2940,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    // Returns `ty::VariantDef` if `def` refers to a struct,
-    // or variant or their constructors, panics otherwise.
+    /// Returns `ty::VariantDef` if `def` refers to a struct,
+    /// or variant or their constructors, panics otherwise.
     pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef {
         match def {
             Def::Variant(did) => {
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 9c908176a6d..796d2f6a18b 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -643,13 +643,18 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
             }
         };
 
-        // Variant constructors have the same visibility as the parent enums.
+        // Variant constructors have the same visibility as the parent enums, unless marked as
+        // non-exhaustive, in which case they are lowered to `pub(crate)`.
         let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap();
         let enum_vis = &tcx.hir().expect_item_by_hir_id(enum_id).vis;
+        let mut ctor_vis = ty::Visibility::from_hir(enum_vis, enum_id, tcx);
+        if variant.is_field_list_non_exhaustive() && ctor_vis == ty::Visibility::Public {
+            ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
+        }
 
         Entry {
             kind: EntryKind::Variant(self.lazy(&data)),
-            visibility: self.lazy(&ty::Visibility::from_hir(enum_vis, enum_id, tcx)),
+            visibility: self.lazy(&ctor_vis),
             span: self.lazy(&tcx.def_span(def_id)),
             attributes: LazySeq::empty(),
             children: LazySeq::empty(),
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 4e2aefe6231..741264d1dbe 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -192,14 +192,6 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn invalid_non_exhaustive_attribute(&self, variant: &Variant) {
-        let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive");
-        if has_non_exhaustive {
-            self.err_handler().span_err(variant.span,
-                                        "#[non_exhaustive] is not yet supported on variants");
-        }
-    }
-
     fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
         if let VisibilityKind::Inherited = vis.node {
             return
@@ -608,7 +600,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             ItemKind::Enum(ref def, _) => {
                 for variant in &def.variants {
-                    self.invalid_non_exhaustive_attribute(variant);
                     for field in variant.node.data.fields() {
                         self.invalid_visibility(&field.vis, None);
                     }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index adb1a4b1308..030883c0159 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -244,7 +244,26 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
                     match tcx.hir().get_by_hir_id(parent_hir_id) {
                         Node::Variant(..) => {
                             let parent_did = tcx.hir().local_def_id_from_hir_id(parent_hir_id);
-                            return def_id_visibility(tcx, parent_did);
+                            let (mut ctor_vis, mut span, mut descr) = def_id_visibility(
+                                tcx, parent_did,
+                            );
+
+                            let adt_def = tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id));
+                            let ctor_did = tcx.hir().local_def_id_from_hir_id(
+                                vdata.ctor_hir_id().unwrap());
+                            let variant = adt_def.variant_with_ctor_id(ctor_did);
+
+                            if variant.is_field_list_non_exhaustive() &&
+                                ctor_vis == ty::Visibility::Public
+                            {
+                                ctor_vis = ty::Visibility::Restricted(
+                                    DefId::local(CRATE_DEF_INDEX));
+                                let attrs = tcx.get_attrs(variant.def_id);
+                                span = attr::find_by_name(&attrs, "non_exhaustive").unwrap().span;
+                                descr = "crate-visible";
+                            }
+
+                            return (ctor_vis, span, descr);
                         }
                         Node::Item(..) => {
                             let item = match tcx.hir().get_by_hir_id(parent_hir_id) {
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index f55425c3168..7ce264db755 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -588,6 +588,14 @@ impl<'a> Resolver<'a> {
         let def = Def::Variant(def_id);
         self.define(parent, ident, TypeNS, (def, vis, variant.span, expansion));
 
+        // If the variant is marked as non_exhaustive then lower the visibility to within the
+        // crate.
+        let mut ctor_vis = vis;
+        let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive");
+        if has_non_exhaustive && vis == ty::Visibility::Public {
+            ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
+        }
+
         // 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.
@@ -597,7 +605,7 @@ impl<'a> Resolver<'a> {
         let ctor_def_id = self.definitions.local_def_id(ctor_node_id);
         let ctor_kind = CtorKind::from_ast(&variant.node.data);
         let ctor_def = Def::Ctor(ctor_def_id, CtorOf::Variant, ctor_kind);
-        self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion));
+        self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, variant.span, expansion));
     }
 
     /// Constructs the reduced graph for one foreign item.
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index cde37fb23c3..22f24df450f 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4341,11 +4341,12 @@ foo.method(); // Ok!
 "##,
 
 E0638: r##"
-This error indicates that the struct or enum must be matched non-exhaustively
-as it has been marked as `non_exhaustive`.
+This error indicates that the struct, enum or enum variant must be matched
+non-exhaustively as it has been marked as `non_exhaustive`.
 
 When applied within a crate, downstream users of the crate will need to use the
 `_` pattern when matching enums and use the `..` pattern when matching structs.
+Downstream crates cannot match against non-exhaustive enum variants.
 
 For example, in the below example, since the enum is marked as
 `non_exhaustive`, it is required that downstream crates match non-exhaustively
@@ -4390,10 +4391,10 @@ Similarly, for structs, match with `..` to avoid this error.
 "##,
 
 E0639: r##"
-This error indicates that the struct or enum cannot be instantiated from
-outside of the defining crate as it has been marked as `non_exhaustive` and as
-such more fields/variants may be added in future that could cause adverse side
-effects for this code.
+This error indicates that the struct, enum or enum variant cannot be
+instantiated from outside of the defining crate as it has been marked
+as `non_exhaustive` and as such more fields/variants may be added in
+future that could cause adverse side effects for this code.
 
 It is recommended that you look for a `new` function or equivalent in the
 crate's documentation.
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 396488c981d..a403f0845ce 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -421,6 +421,9 @@ impl Item {
     pub fn is_enum(&self) -> bool {
         self.type_() == ItemType::Enum
     }
+    pub fn is_variant(&self) -> bool {
+        self.type_() == ItemType::Variant
+    }
     pub fn is_associated_type(&self) -> bool {
         self.type_() == ItemType::AssociatedType
     }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 866d8fe682a..9220d2feed2 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2604,7 +2604,15 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str {
 fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fmt::Result {
     if item.is_non_exhaustive() {
         write!(w, "<div class='docblock non-exhaustive non-exhaustive-{}'>", {
-            if item.is_struct() { "struct" } else if item.is_enum() { "enum" } else { "type" }
+            if item.is_struct() {
+                "struct"
+            } else if item.is_enum() {
+                "enum"
+            } else if item.is_variant() {
+                "variant"
+            } else {
+                "type"
+            }
         })?;
 
         if item.is_struct() {
@@ -2617,6 +2625,10 @@ fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fm
             write!(w, "Non-exhaustive enums could have additional variants added in future. \
                        Therefore, when matching against variants of non-exhaustive enums, an \
                        extra wildcard arm must be added to account for any future variants.")?;
+        } else if item.is_variant() {
+            write!(w, "Non-exhaustive enum variants could have additional fields added in future. \
+                       Therefore, non-exhaustive enum variants cannot be constructed in external \
+                       crates and cannot be matched against.")?;
         } else {
             write!(w, "This type will require a wildcard arm in any match statements or \
                        constructors.")?;
@@ -3679,6 +3691,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
             }
             write!(w, "</code></span>")?;
             document(w, cx, variant)?;
+            document_non_exhaustive(w, variant)?;
 
             use crate::clean::{Variant, VariantKind};
             if let clean::VariantItem(Variant {
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index aad7eb627bf..f7fb97dcb4b 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -2263,6 +2263,8 @@ if (!DOMTokenList.prototype.remove) {
                     otherMessage += "struct";
                 } else if (hasClass(e, "non-exhaustive-enum")) {
                     otherMessage += "enum";
+                } else if (hasClass(e, "non-exhaustive-variant")) {
+                    otherMessage += "enum variant";
                 } else if (hasClass(e, "non-exhaustive-type")) {
                     otherMessage += "type";
                 }
@@ -2280,6 +2282,9 @@ if (!DOMTokenList.prototype.remove) {
             if (hasClass(e, "type-decl") === true && showItemDeclarations === true) {
                 collapseDocs(e.previousSibling.childNodes[0], "toggle");
             }
+            if (hasClass(e, "non-exhaustive") === true) {
+                collapseDocs(e.previousSibling.childNodes[0], "toggle");
+            }
         }
     }
 
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs
deleted file mode 100644
index b3e2fa2c620..00000000000
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// run-pass
-#![crate_type = "rlib"]
-#![feature(non_exhaustive)]
-
-#[non_exhaustive]
-pub enum NonExhaustiveEnum {
-    Unit,
-    Tuple(u32),
-    Struct { field: u32 }
-}
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs
deleted file mode 100644
index 08b14d0df94..00000000000
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// run-pass
-#![feature(non_exhaustive)]
-
-#[non_exhaustive]
-pub struct NormalStruct {
-    pub first_field: u16,
-    pub second_field: u16,
-}
-
-#[non_exhaustive]
-pub struct UnitStruct;
-
-#[non_exhaustive]
-pub struct TupleStruct (pub u16, pub u16);
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs
deleted file mode 100644
index 56a73d8ab60..00000000000
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-// run-pass
-#![crate_type = "rlib"]
-#![feature(non_exhaustive)]
-
-pub enum NonExhaustiveVariants {
-    #[non_exhaustive] Unit,
-    #[non_exhaustive] Tuple(u32),
-    #[non_exhaustive] Struct { field: u32 }
-}
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs
deleted file mode 100644
index f7e9c538496..00000000000
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-// run-pass
-// aux-build:enums.rs
-extern crate enums;
-
-// ignore-pretty issue #37199
-
-use enums::NonExhaustiveEnum;
-
-fn main() {
-    let enum_unit = NonExhaustiveEnum::Unit;
-
-    match enum_unit {
-        NonExhaustiveEnum::Unit => 1,
-        NonExhaustiveEnum::Tuple(_) => 2,
-        // This particular arm tests that a enum marked as non-exhaustive
-        // will not error if its variants are matched exhaustively.
-        NonExhaustiveEnum::Struct { field } => field,
-        _ => 0 // no error with wildcard
-    };
-
-    match enum_unit {
-        _ => "no error with only wildcard"
-    };
-
-
-    // issue #53549 - check that variant constructors can still be called normally.
-
-    match NonExhaustiveEnum::Unit {
-        NonExhaustiveEnum::Unit => {},
-        _ => {}
-    };
-
-    match NonExhaustiveEnum::Tuple(2) {
-        NonExhaustiveEnum::Tuple(2) => {},
-        _ => {}
-    };
-
-    match (NonExhaustiveEnum::Unit {}) {
-        NonExhaustiveEnum::Unit {} => {},
-        _ => {}
-    };
-
-    match (NonExhaustiveEnum::Tuple { 0: 2 }) {
-        NonExhaustiveEnum::Tuple { 0: 2 } => {},
-        _ => {}
-    };
-
-    match (NonExhaustiveEnum::Struct { field: 2 }) {
-        NonExhaustiveEnum::Struct { field: 2 } => {},
-        _ => {}
-    };
-
-}
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs
deleted file mode 100644
index 3cd7234269e..00000000000
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-#![allow(unused_variables)]
-// aux-build:structs.rs
-extern crate structs;
-
-use structs::{NormalStruct, UnitStruct, TupleStruct};
-
-// We only test matching here as we cannot create non-exhaustive
-// structs from another crate. ie. they'll never pass in run-pass tests.
-
-fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) {
-    let NormalStruct { first_field, second_field, .. } = ns;
-
-    let TupleStruct { 0: first, 1: second, .. } = ts;
-
-    let UnitStruct { .. } = us;
-}
-
-fn main() { }
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs
deleted file mode 100644
index 90b8219e2a3..00000000000
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// run-pass
-// aux-build:variants.rs
-extern crate variants;
-
-use variants::NonExhaustiveVariants;
-
-/*
- * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
- * variants. See issue #44109 and PR 45394.
- */
-// ignore-test
-
-fn main() {
-    let variant_tuple = NonExhaustiveVariants::Tuple { 0: 340 };
-    let variant_struct = NonExhaustiveVariants::Struct { field: 340 };
-
-    match variant_struct {
-        NonExhaustiveVariants::Unit => "",
-        NonExhaustiveVariants::Struct { field, .. } => "",
-        NonExhaustiveVariants::Tuple(fe_tpl, ..) => ""
-    };
-}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.rs b/src/test/ui/rfc-2008-non-exhaustive/enum.rs
index d9b1a989510..7423a970e2e 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum.rs
@@ -12,4 +12,48 @@ fn main() {
         NonExhaustiveEnum::Tuple(_) => "second",
         NonExhaustiveEnum::Struct { .. } => "third"
     };
+
+    // Everything below this is expected to compile successfully.
+
+    let enum_unit = NonExhaustiveEnum::Unit;
+
+    match enum_unit {
+        NonExhaustiveEnum::Unit => 1,
+        NonExhaustiveEnum::Tuple(_) => 2,
+        // This particular arm tests that a enum marked as non-exhaustive
+        // will not error if its variants are matched exhaustively.
+        NonExhaustiveEnum::Struct { field } => field,
+        _ => 0 // no error with wildcard
+    };
+
+    match enum_unit {
+        _ => "no error with only wildcard"
+    };
+
+    // #53549: Check that variant constructors can still be called normally.
+    match NonExhaustiveEnum::Unit {
+        NonExhaustiveEnum::Unit => {},
+        _ => {}
+    };
+
+    match NonExhaustiveEnum::Tuple(2) {
+        NonExhaustiveEnum::Tuple(2) => {},
+        _ => {}
+    };
+
+    match (NonExhaustiveEnum::Unit {}) {
+        NonExhaustiveEnum::Unit {} => {},
+        _ => {}
+    };
+
+    match (NonExhaustiveEnum::Tuple { 0: 2 }) {
+        NonExhaustiveEnum::Tuple { 0: 2 } => {},
+        _ => {}
+    };
+
+    match (NonExhaustiveEnum::Struct { field: 2 }) {
+        NonExhaustiveEnum::Struct { field: 2 } => {},
+        _ => {}
+    };
+
 }
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs
index 384e099275e..a3626bf60b2 100644
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs
@@ -1,4 +1,5 @@
 // run-pass
+
 #![feature(non_exhaustive)]
 
 #[non_exhaustive]
diff --git a/src/test/ui/rfc-2008-non-exhaustive/structs.rs b/src/test/ui/rfc-2008-non-exhaustive/struct.rs
index 303d71d12df..94ac588d240 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/structs.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/struct.rs
@@ -35,3 +35,15 @@ fn main() {
     let UnitStruct { } = us;
     //~^ ERROR `..` required with struct marked as non-exhaustive
 }
+
+// Everything below this is expected to compile successfully.
+
+// We only test matching here as we cannot create non-exhaustive
+// structs from another crate. ie. they'll never pass in run-pass tests.
+fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) {
+    let NormalStruct { first_field, second_field, .. } = ns;
+
+    let TupleStruct { 0: first, 1: second, .. } = ts;
+
+    let UnitStruct { .. } = us;
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/structs.stderr b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr
index 6213c392a9b..ecfad88a825 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/structs.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr
@@ -1,29 +1,29 @@
 error[E0423]: expected function, found struct `TupleStruct`
-  --> $DIR/structs.rs:20:14
+  --> $DIR/struct.rs:20:14
    |
 LL |     let ts = TupleStruct(640, 480);
    |              ^^^^^^^^^^^ constructor is not visible here due to private fields
 
 error[E0423]: expected value, found struct `UnitStruct`
-  --> $DIR/structs.rs:29:14
+  --> $DIR/struct.rs:29:14
    |
 LL |     let us = UnitStruct;
    |              ^^^^^^^^^^ constructor is not visible here due to private fields
 
 error[E0603]: tuple struct `TupleStruct` is private
-  --> $DIR/structs.rs:23:32
+  --> $DIR/struct.rs:23:32
    |
 LL |     let ts_explicit = structs::TupleStruct(640, 480);
    |                                ^^^^^^^^^^^
 
 error[E0603]: unit struct `UnitStruct` is private
-  --> $DIR/structs.rs:32:32
+  --> $DIR/struct.rs:32:32
    |
 LL |     let us_explicit = structs::UnitStruct;
    |                                ^^^^^^^^^^
 
 error[E0639]: cannot create non-exhaustive struct using struct expression
-  --> $DIR/structs.rs:7:14
+  --> $DIR/struct.rs:7:14
    |
 LL |       let fr = FunctionalRecord {
    |  ______________^
@@ -35,25 +35,25 @@ LL | |     };
    | |_____^
 
 error[E0639]: cannot create non-exhaustive struct using struct expression
-  --> $DIR/structs.rs:14:14
+  --> $DIR/struct.rs:14:14
    |
 LL |     let ns = NormalStruct { first_field: 640, second_field: 480 };
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0638]: `..` required with struct marked as non-exhaustive
-  --> $DIR/structs.rs:17:9
+  --> $DIR/struct.rs:17:9
    |
 LL |     let NormalStruct { first_field, second_field } = ns;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0638]: `..` required with struct marked as non-exhaustive
-  --> $DIR/structs.rs:26:9
+  --> $DIR/struct.rs:26:9
    |
 LL |     let TupleStruct { 0: first_field, 1: second_field } = ts;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0638]: `..` required with struct marked as non-exhaustive
-  --> $DIR/structs.rs:35:9
+  --> $DIR/struct.rs:35:9
    |
 LL |     let UnitStruct { } = us;
    |         ^^^^^^^^^^^^^^
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs
index 5e71cce1297..2b1d7d9ac50 100644
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs
@@ -1,4 +1,5 @@
 // run-pass
+
 #![allow(unused_variables)]
 #![feature(non_exhaustive)]
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants.rs b/src/test/ui/rfc-2008-non-exhaustive/variant.rs
index 373bbc3547f..bc346aea51c 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/variants.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/variant.rs
@@ -1,26 +1,33 @@
 // aux-build:variants.rs
+
 extern crate variants;
 
 use variants::NonExhaustiveVariants;
 
-/*
- * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
- * variants. See issue #44109 and PR 45394.
- */
-// ignore-test
-
 fn main() {
     let variant_struct = NonExhaustiveVariants::Struct { field: 640 };
     //~^ ERROR cannot create non-exhaustive variant
 
-    let variant_tuple = NonExhaustiveVariants::Tuple { 0: 640 };
-    //~^ ERROR cannot create non-exhaustive variant
+    let variant_tuple = NonExhaustiveVariants::Tuple(640);
+    //~^ ERROR tuple variant `Tuple` is private [E0603]
+
+    let variant_unit = NonExhaustiveVariants::Unit;
+    //~^ ERROR unit variant `Unit` is private [E0603]
 
     match variant_struct {
         NonExhaustiveVariants::Unit => "",
+        //~^ ERROR unit variant `Unit` is private [E0603]
         NonExhaustiveVariants::Tuple(fe_tpl) => "",
-        //~^ ERROR `..` required with variant marked as non-exhaustive
+        //~^ ERROR tuple variant `Tuple` is private [E0603]
         NonExhaustiveVariants::Struct { field } => ""
         //~^ ERROR `..` required with variant marked as non-exhaustive
     };
+
+    if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct {
+        //~^ ERROR tuple variant `Tuple` is private [E0603]
+    }
+
+    if let NonExhaustiveVariants::Struct { field } = variant_struct {
+        //~^ ERROR `..` required with variant marked as non-exhaustive
+    }
 }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/variant.stderr b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr
new file mode 100644
index 00000000000..edfca789150
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr
@@ -0,0 +1,52 @@
+error[E0603]: tuple variant `Tuple` is private
+  --> $DIR/variant.rs:11:48
+   |
+LL |     let variant_tuple = NonExhaustiveVariants::Tuple(640);
+   |                                                ^^^^^
+
+error[E0603]: unit variant `Unit` is private
+  --> $DIR/variant.rs:14:47
+   |
+LL |     let variant_unit = NonExhaustiveVariants::Unit;
+   |                                               ^^^^
+
+error[E0603]: unit variant `Unit` is private
+  --> $DIR/variant.rs:18:32
+   |
+LL |         NonExhaustiveVariants::Unit => "",
+   |                                ^^^^
+
+error[E0603]: tuple variant `Tuple` is private
+  --> $DIR/variant.rs:20:32
+   |
+LL |         NonExhaustiveVariants::Tuple(fe_tpl) => "",
+   |                                ^^^^^
+
+error[E0603]: tuple variant `Tuple` is private
+  --> $DIR/variant.rs:26:35
+   |
+LL |     if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct {
+   |                                   ^^^^^
+
+error[E0639]: cannot create non-exhaustive variant using struct expression
+  --> $DIR/variant.rs:8:26
+   |
+LL |     let variant_struct = NonExhaustiveVariants::Struct { field: 640 };
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0638]: `..` required with variant marked as non-exhaustive
+  --> $DIR/variant.rs:22:9
+   |
+LL |         NonExhaustiveVariants::Struct { field } => ""
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0638]: `..` required with variant marked as non-exhaustive
+  --> $DIR/variant.rs:30:12
+   |
+LL |     if let NonExhaustiveVariants::Struct { field } = variant_struct {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
+Some errors occurred: E0603, E0638, E0639.
+For more information about an error, try `rustc --explain E0603`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants_create.rs b/src/test/ui/rfc-2008-non-exhaustive/variants_create.rs
deleted file mode 100644
index 9ed244144df..00000000000
--- a/src/test/ui/rfc-2008-non-exhaustive/variants_create.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-#![feature(non_exhaustive)]
-
-/*
- * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
- * variants. See issue #44109 and PR 45394.
- */
-
-pub enum NonExhaustiveVariants {
-    #[non_exhaustive] Unit,
-    //~^ ERROR #[non_exhaustive] is not yet supported on variants
-    #[non_exhaustive] Tuple(u32),
-    //~^ ERROR #[non_exhaustive] is not yet supported on variants
-    #[non_exhaustive] Struct { field: u32 }
-    //~^ ERROR #[non_exhaustive] is not yet supported on variants
-}
-
-fn main() { }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr b/src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr
deleted file mode 100644
index 5b099d58ec4..00000000000
--- a/src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: #[non_exhaustive] is not yet supported on variants
-  --> $DIR/variants_create.rs:9:23
-   |
-LL |     #[non_exhaustive] Unit,
-   |                       ^^^^
-
-error: #[non_exhaustive] is not yet supported on variants
-  --> $DIR/variants_create.rs:11:23
-   |
-LL |     #[non_exhaustive] Tuple(u32),
-   |                       ^^^^^^^^^^
-
-error: #[non_exhaustive] is not yet supported on variants
-  --> $DIR/variants_create.rs:13:23
-   |
-LL |     #[non_exhaustive] Struct { field: u32 }
-   |                       ^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs
index 603e69b9ff9..470a5ea9833 100644
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs
@@ -1,11 +1,6 @@
 // run-pass
-#![feature(non_exhaustive)]
 
-/*
- * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
- * variants. See issue #44109 and PR 45394.
- */
-// ignore-test
+#![feature(non_exhaustive)]
 
 pub enum NonExhaustiveVariants {
     #[non_exhaustive] Unit,