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 f9840e1b83f2b..907147c17ef8e 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 f0045136f41bf..102057c1380ac 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 78a186fbb714a..84237cc1e7133 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -642,13 +642,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 4e2aefe623167..741264d1dbe18 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 bbd03e82a3730..8c3d80b323ffd 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 f55425c3168ec..7ce264db755db 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 cde37fb23c320..22f24df450f46 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 61dbf00a1f536..114294cde4ee2 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 445ce0637662d..982c033be99fd 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2596,7 +2596,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, "
", {
- 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() {
@@ -2609,6 +2617,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.")?;
@@ -3671,6 +3683,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
}
write!(w, "")?;
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 fef6910f40a57..85dc4d57337c8 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -2247,6 +2247,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";
}
@@ -2264,6 +2266,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 b3e2fa2c6208e..0000000000000
--- 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 08b14d0df9408..0000000000000
--- 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 56a73d8ab6088..0000000000000
--- 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 f7e9c53849612..0000000000000
--- 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 3cd7234269e1d..0000000000000
--- 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 90b8219e2a3c0..0000000000000
--- 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 d9b1a9895104c..7423a970e2e3b 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
similarity index 99%
rename from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs
rename to src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs
index 384e099275e9b..a3626bf60b260 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
similarity index 73%
rename from src/test/ui/rfc-2008-non-exhaustive/structs.rs
rename to src/test/ui/rfc-2008-non-exhaustive/struct.rs
index 303d71d12df33..94ac588d24083 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
similarity index 88%
rename from src/test/ui/rfc-2008-non-exhaustive/structs.stderr
rename to src/test/ui/rfc-2008-non-exhaustive/struct.stderr
index 6213c392a9b47..ecfad88a82552 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
similarity index 99%
rename from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs
rename to src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs
index 5e71cce1297cb..2b1d7d9ac5030 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
similarity index 50%
rename from src/test/ui/rfc-2008-non-exhaustive/variants.rs
rename to src/test/ui/rfc-2008-non-exhaustive/variant.rs
index 373bbc3547f38..bc346aea51cfc 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 0000000000000..edfca78915017
--- /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 9ed244144dff9..0000000000000
--- 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 5b099d58ec467..0000000000000
--- 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
similarity index 76%
rename from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs
rename to src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs
index 603e69b9ff9b0..470a5ea9833ad 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,