1
Fork 0

Rollup merge of #59376 - davidtwco:finally-rfc-2008-variants, r=petrochenkov,QuietMisdreavus

RFC 2008: Enum Variants

Part of #44109. See [Zulip topic](132663140) for previous discussion.

r? @petrochenkov
cc @nikomatsakis
This commit is contained in:
Mazdak Farrokhzad 2019-03-30 07:51:34 +01:00 committed by GitHub
commit d050a157a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 219 additions and 216 deletions

View file

@ -7,10 +7,12 @@ The tracking issue for this feature is: [#44109]
------------------------ ------------------------
The `non_exhaustive` gate allows you to use the `#[non_exhaustive]` attribute 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 on structs, enums and enum variants. When applied within a crate, users of the
to use the `_` pattern when matching enums and use the `..` pattern when crate will need to use the `_` pattern when matching enums and use the `..`
matching structs. Structs marked as `non_exhaustive` will not be able to be pattern when matching structs. Enum variants cannot be matched against.
created normally outside of the defining crate. This is demonstrated below: 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) ```rust,ignore (pseudo-Rust)
use std::error::Error as StdError; use std::error::Error as StdError;
@ -72,4 +74,3 @@ let config = Config { window_width: 640, window_height: 480 };
// when marked non_exhaustive. // when marked non_exhaustive.
let &Config { window_width, window_height, .. } = config; let &Config { window_width, window_height, .. } = config;
``` ```

View file

@ -1869,6 +1869,11 @@ impl<'a, 'gcx, 'tcx> VariantDef {
if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, "non_exhaustive") { if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, "non_exhaustive") {
debug!("found non-exhaustive field list for {:?}", parent_did); debug!("found non-exhaustive field list for {:?}", parent_did);
flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE; 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 { VariantDef {
@ -2146,6 +2151,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
debug!("found non-exhaustive variant list for {:?}", did); debug!("found non-exhaustive variant list for {:?}", did);
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE; flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
} }
flags |= match kind { flags |= match kind {
AdtKind::Enum => AdtFlags::IS_ENUM, AdtKind::Enum => AdtFlags::IS_ENUM,
AdtKind::Union => AdtFlags::IS_UNION, AdtKind::Union => AdtFlags::IS_UNION,
@ -2299,21 +2305,25 @@ impl<'a, 'gcx, 'tcx> AdtDef {
self.variants.iter().all(|v| v.fields.is_empty()) 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 { pub fn variant_with_id(&self, vid: DefId) -> &VariantDef {
self.variants.iter().find(|v| v.def_id == vid) self.variants.iter().find(|v| v.def_id == vid)
.expect("variant_with_id: unknown variant") .expect("variant_with_id: unknown variant")
} }
/// Return a `VariantDef` given a constructor id.
pub fn variant_with_ctor_id(&self, cid: DefId) -> &VariantDef { pub fn variant_with_ctor_id(&self, cid: DefId) -> &VariantDef {
self.variants.iter().find(|v| v.ctor_def_id == Some(cid)) self.variants.iter().find(|v| v.ctor_def_id == Some(cid))
.expect("variant_with_ctor_id: unknown variant") .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 { pub fn variant_index_with_id(&self, vid: DefId) -> VariantIdx {
self.variants.iter_enumerated().find(|(_, v)| v.def_id == vid) self.variants.iter_enumerated().find(|(_, v)| v.def_id == vid)
.expect("variant_index_with_id: unknown variant").0 .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 { pub fn variant_index_with_ctor_id(&self, cid: DefId) -> VariantIdx {
self.variants.iter_enumerated().find(|(_, v)| v.ctor_def_id == Some(cid)) self.variants.iter_enumerated().find(|(_, v)| v.ctor_def_id == Some(cid))
.expect("variant_index_with_ctor_id: unknown variant").0 .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, /// Returns `ty::VariantDef` if `def` refers to a struct,
// or variant or their constructors, panics otherwise. /// or variant or their constructors, panics otherwise.
pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef { pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef {
match def { match def {
Def::Variant(did) => { Def::Variant(did) => {

View file

@ -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_id = tcx.hir().as_local_hir_id(enum_did).unwrap();
let enum_vis = &tcx.hir().expect_item_by_hir_id(enum_id).vis; 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 { Entry {
kind: EntryKind::Variant(self.lazy(&data)), 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)), span: self.lazy(&tcx.def_span(def_id)),
attributes: LazySeq::empty(), attributes: LazySeq::empty(),
children: LazySeq::empty(), children: LazySeq::empty(),

View file

@ -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>) { fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
if let VisibilityKind::Inherited = vis.node { if let VisibilityKind::Inherited = vis.node {
return return
@ -608,7 +600,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
} }
ItemKind::Enum(ref def, _) => { ItemKind::Enum(ref def, _) => {
for variant in &def.variants { for variant in &def.variants {
self.invalid_non_exhaustive_attribute(variant);
for field in variant.node.data.fields() { for field in variant.node.data.fields() {
self.invalid_visibility(&field.vis, None); self.invalid_visibility(&field.vis, None);
} }

View file

@ -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) { match tcx.hir().get_by_hir_id(parent_hir_id) {
Node::Variant(..) => { Node::Variant(..) => {
let parent_did = tcx.hir().local_def_id_from_hir_id(parent_hir_id); 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(..) => { Node::Item(..) => {
let item = match tcx.hir().get_by_hir_id(parent_hir_id) { let item = match tcx.hir().get_by_hir_id(parent_hir_id) {

View file

@ -588,6 +588,14 @@ impl<'a> Resolver<'a> {
let def = Def::Variant(def_id); let def = Def::Variant(def_id);
self.define(parent, ident, TypeNS, (def, vis, variant.span, expansion)); 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. // Define a constructor name in the value namespace.
// Braced variants, unlike structs, generate unusable names in // Braced variants, unlike structs, generate unusable names in
// value namespace, they are reserved for possible future use. // 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_def_id = self.definitions.local_def_id(ctor_node_id);
let ctor_kind = CtorKind::from_ast(&variant.node.data); let ctor_kind = CtorKind::from_ast(&variant.node.data);
let ctor_def = Def::Ctor(ctor_def_id, CtorOf::Variant, ctor_kind); let ctor_def = Def::Ctor(ctor_def_id, CtorOf::Variant, ctor_kind);
self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion)); self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, variant.span, expansion));
} }
/// Constructs the reduced graph for one foreign item. /// Constructs the reduced graph for one foreign item.

View file

@ -4341,11 +4341,12 @@ foo.method(); // Ok!
"##, "##,
E0638: r##" E0638: r##"
This error indicates that the struct or enum must be matched non-exhaustively This error indicates that the struct, enum or enum variant must be matched
as it has been marked as `non_exhaustive`. 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 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. `_` 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 For example, in the below example, since the enum is marked as
`non_exhaustive`, it is required that downstream crates match non-exhaustively `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##" E0639: r##"
This error indicates that the struct or enum cannot be instantiated from This error indicates that the struct, enum or enum variant cannot be
outside of the defining crate as it has been marked as `non_exhaustive` and as instantiated from outside of the defining crate as it has been marked
such more fields/variants may be added in future that could cause adverse side as `non_exhaustive` and as such more fields/variants may be added in
effects for this code. future that could cause adverse side effects for this code.
It is recommended that you look for a `new` function or equivalent in the It is recommended that you look for a `new` function or equivalent in the
crate's documentation. crate's documentation.

View file

@ -421,6 +421,9 @@ impl Item {
pub fn is_enum(&self) -> bool { pub fn is_enum(&self) -> bool {
self.type_() == ItemType::Enum self.type_() == ItemType::Enum
} }
pub fn is_variant(&self) -> bool {
self.type_() == ItemType::Variant
}
pub fn is_associated_type(&self) -> bool { pub fn is_associated_type(&self) -> bool {
self.type_() == ItemType::AssociatedType self.type_() == ItemType::AssociatedType
} }

View file

@ -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 { fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fmt::Result {
if item.is_non_exhaustive() { if item.is_non_exhaustive() {
write!(w, "<div class='docblock non-exhaustive 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() { 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. \ write!(w, "Non-exhaustive enums could have additional variants added in future. \
Therefore, when matching against variants of non-exhaustive enums, an \ Therefore, when matching against variants of non-exhaustive enums, an \
extra wildcard arm must be added to account for any future variants.")?; 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 { } else {
write!(w, "This type will require a wildcard arm in any match statements or \ write!(w, "This type will require a wildcard arm in any match statements or \
constructors.")?; constructors.")?;
@ -3679,6 +3691,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
} }
write!(w, "</code></span>")?; write!(w, "</code></span>")?;
document(w, cx, variant)?; document(w, cx, variant)?;
document_non_exhaustive(w, variant)?;
use crate::clean::{Variant, VariantKind}; use crate::clean::{Variant, VariantKind};
if let clean::VariantItem(Variant { if let clean::VariantItem(Variant {

View file

@ -2263,6 +2263,8 @@ if (!DOMTokenList.prototype.remove) {
otherMessage += "struct"; otherMessage += "struct";
} else if (hasClass(e, "non-exhaustive-enum")) { } else if (hasClass(e, "non-exhaustive-enum")) {
otherMessage += "enum"; otherMessage += "enum";
} else if (hasClass(e, "non-exhaustive-variant")) {
otherMessage += "enum variant";
} else if (hasClass(e, "non-exhaustive-type")) { } else if (hasClass(e, "non-exhaustive-type")) {
otherMessage += "type"; otherMessage += "type";
} }
@ -2280,6 +2282,9 @@ if (!DOMTokenList.prototype.remove) {
if (hasClass(e, "type-decl") === true && showItemDeclarations === true) { if (hasClass(e, "type-decl") === true && showItemDeclarations === true) {
collapseDocs(e.previousSibling.childNodes[0], "toggle"); collapseDocs(e.previousSibling.childNodes[0], "toggle");
} }
if (hasClass(e, "non-exhaustive") === true) {
collapseDocs(e.previousSibling.childNodes[0], "toggle");
}
} }
} }

View file

@ -1,10 +0,0 @@
// run-pass
#![crate_type = "rlib"]
#![feature(non_exhaustive)]
#[non_exhaustive]
pub enum NonExhaustiveEnum {
Unit,
Tuple(u32),
Struct { field: u32 }
}

View file

@ -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);

View file

@ -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 }
}

View file

@ -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 } => {},
_ => {}
};
}

View file

@ -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() { }

View file

@ -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, ..) => ""
};
}

View file

@ -12,4 +12,48 @@ fn main() {
NonExhaustiveEnum::Tuple(_) => "second", NonExhaustiveEnum::Tuple(_) => "second",
NonExhaustiveEnum::Struct { .. } => "third" 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 } => {},
_ => {}
};
} }

View file

@ -1,4 +1,5 @@
// run-pass // run-pass
#![feature(non_exhaustive)] #![feature(non_exhaustive)]
#[non_exhaustive] #[non_exhaustive]

View file

@ -35,3 +35,15 @@ fn main() {
let UnitStruct { } = us; let UnitStruct { } = us;
//~^ ERROR `..` required with struct marked as non-exhaustive //~^ 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;
}

View file

@ -1,29 +1,29 @@
error[E0423]: expected function, found struct `TupleStruct` error[E0423]: expected function, found struct `TupleStruct`
--> $DIR/structs.rs:20:14 --> $DIR/struct.rs:20:14
| |
LL | let ts = TupleStruct(640, 480); LL | let ts = TupleStruct(640, 480);
| ^^^^^^^^^^^ constructor is not visible here due to private fields | ^^^^^^^^^^^ constructor is not visible here due to private fields
error[E0423]: expected value, found struct `UnitStruct` error[E0423]: expected value, found struct `UnitStruct`
--> $DIR/structs.rs:29:14 --> $DIR/struct.rs:29:14
| |
LL | let us = UnitStruct; LL | let us = UnitStruct;
| ^^^^^^^^^^ constructor is not visible here due to private fields | ^^^^^^^^^^ constructor is not visible here due to private fields
error[E0603]: tuple struct `TupleStruct` is private 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); LL | let ts_explicit = structs::TupleStruct(640, 480);
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error[E0603]: unit struct `UnitStruct` is private error[E0603]: unit struct `UnitStruct` is private
--> $DIR/structs.rs:32:32 --> $DIR/struct.rs:32:32
| |
LL | let us_explicit = structs::UnitStruct; LL | let us_explicit = structs::UnitStruct;
| ^^^^^^^^^^ | ^^^^^^^^^^
error[E0639]: cannot create non-exhaustive struct using struct expression error[E0639]: cannot create non-exhaustive struct using struct expression
--> $DIR/structs.rs:7:14 --> $DIR/struct.rs:7:14
| |
LL | let fr = FunctionalRecord { LL | let fr = FunctionalRecord {
| ______________^ | ______________^
@ -35,25 +35,25 @@ LL | | };
| |_____^ | |_____^
error[E0639]: cannot create non-exhaustive struct using struct expression 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 }; LL | let ns = NormalStruct { first_field: 640, second_field: 480 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0638]: `..` required with struct marked as non-exhaustive 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; LL | let NormalStruct { first_field, second_field } = ns;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0638]: `..` required with struct marked as non-exhaustive 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; LL | let TupleStruct { 0: first_field, 1: second_field } = ts;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0638]: `..` required with struct marked as non-exhaustive error[E0638]: `..` required with struct marked as non-exhaustive
--> $DIR/structs.rs:35:9 --> $DIR/struct.rs:35:9
| |
LL | let UnitStruct { } = us; LL | let UnitStruct { } = us;
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^

View file

@ -1,4 +1,5 @@
// run-pass // run-pass
#![allow(unused_variables)] #![allow(unused_variables)]
#![feature(non_exhaustive)] #![feature(non_exhaustive)]

View file

@ -1,26 +1,33 @@
// aux-build:variants.rs // aux-build:variants.rs
extern crate variants; extern crate variants;
use variants::NonExhaustiveVariants; 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() { fn main() {
let variant_struct = NonExhaustiveVariants::Struct { field: 640 }; let variant_struct = NonExhaustiveVariants::Struct { field: 640 };
//~^ ERROR cannot create non-exhaustive variant //~^ ERROR cannot create non-exhaustive variant
let variant_tuple = NonExhaustiveVariants::Tuple { 0: 640 }; let variant_tuple = NonExhaustiveVariants::Tuple(640);
//~^ ERROR cannot create non-exhaustive variant //~^ ERROR tuple variant `Tuple` is private [E0603]
let variant_unit = NonExhaustiveVariants::Unit;
//~^ ERROR unit variant `Unit` is private [E0603]
match variant_struct { match variant_struct {
NonExhaustiveVariants::Unit => "", NonExhaustiveVariants::Unit => "",
//~^ ERROR unit variant `Unit` is private [E0603]
NonExhaustiveVariants::Tuple(fe_tpl) => "", NonExhaustiveVariants::Tuple(fe_tpl) => "",
//~^ ERROR `..` required with variant marked as non-exhaustive //~^ ERROR tuple variant `Tuple` is private [E0603]
NonExhaustiveVariants::Struct { field } => "" NonExhaustiveVariants::Struct { field } => ""
//~^ ERROR `..` required with variant marked as non-exhaustive //~^ 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
}
} }

View file

@ -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`.

View file

@ -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() { }

View file

@ -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

View file

@ -1,11 +1,6 @@
// run-pass // run-pass
#![feature(non_exhaustive)]
/* #![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
pub enum NonExhaustiveVariants { pub enum NonExhaustiveVariants {
#[non_exhaustive] Unit, #[non_exhaustive] Unit,