Skip to content

Commit 3a88cd7

Browse files
committed
Implement #[non_exhaustive] on variants.
This commit removes the check that disallows the `#[non_exhaustive]` attribute from being placed on enum variants and removes the associated tests. Further, this commit lowers the visibility of enum variant constructors when the variant is marked as non-exhaustive.
1 parent 4187560 commit 3a88cd7

File tree

21 files changed

+179
-204
lines changed

21 files changed

+179
-204
lines changed

src/librustc/ty/mod.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1869,6 +1869,11 @@ impl<'a, 'gcx, 'tcx> VariantDef {
18691869
if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, "non_exhaustive") {
18701870
debug!("found non-exhaustive field list for {:?}", parent_did);
18711871
flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
1872+
} else if let Some(variant_did) = variant_did {
1873+
if tcx.has_attr(variant_did, "non_exhaustive") {
1874+
debug!("found non-exhaustive field list for {:?}", variant_did);
1875+
flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
1876+
}
18721877
}
18731878

18741879
VariantDef {
@@ -2935,8 +2940,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
29352940
}
29362941
}
29372942

2938-
// Returns `ty::VariantDef` if `def` refers to a struct,
2939-
// or variant or their constructors, panics otherwise.
2943+
/// Returns `ty::VariantDef` if `def` refers to a struct,
2944+
/// or variant or their constructors, panics otherwise.
29402945
pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef {
29412946
match def {
29422947
Def::Variant(did) => {

src/librustc_metadata/encoder.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -642,13 +642,18 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
642642
}
643643
};
644644

645-
// Variant constructors have the same visibility as the parent enums.
645+
// Variant constructors have the same visibility as the parent enums, unless marked as
646+
// non-exhaustive, in which case they are lowered to `pub(crate)`.
646647
let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap();
647648
let enum_vis = &tcx.hir().expect_item_by_hir_id(enum_id).vis;
649+
let mut ctor_vis = ty::Visibility::from_hir(enum_vis, enum_id, tcx);
650+
if variant.is_field_list_non_exhaustive() && ctor_vis == ty::Visibility::Public {
651+
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
652+
}
648653

649654
Entry {
650655
kind: EntryKind::Variant(self.lazy(&data)),
651-
visibility: self.lazy(&ty::Visibility::from_hir(enum_vis, enum_id, tcx)),
656+
visibility: self.lazy(&ctor_vis),
652657
span: self.lazy(&tcx.def_span(def_id)),
653658
attributes: LazySeq::empty(),
654659
children: LazySeq::empty(),

src/librustc_passes/ast_validation.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,6 @@ impl<'a> AstValidator<'a> {
192192
}
193193
}
194194

195-
fn invalid_non_exhaustive_attribute(&self, variant: &Variant) {
196-
let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive");
197-
if has_non_exhaustive {
198-
self.err_handler().span_err(variant.span,
199-
"#[non_exhaustive] is not yet supported on variants");
200-
}
201-
}
202-
203195
fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
204196
if let VisibilityKind::Inherited = vis.node {
205197
return
@@ -608,7 +600,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
608600
}
609601
ItemKind::Enum(ref def, _) => {
610602
for variant in &def.variants {
611-
self.invalid_non_exhaustive_attribute(variant);
612603
for field in variant.node.data.fields() {
613604
self.invalid_visibility(&field.vis, None);
614605
}

src/librustc_privacy/lib.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,26 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
244244
match tcx.hir().get_by_hir_id(parent_hir_id) {
245245
Node::Variant(..) => {
246246
let parent_did = tcx.hir().local_def_id_from_hir_id(parent_hir_id);
247-
return def_id_visibility(tcx, parent_did);
247+
let (mut ctor_vis, mut span, mut descr) = def_id_visibility(
248+
tcx, parent_did,
249+
);
250+
251+
let adt_def = tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id));
252+
let ctor_did = tcx.hir().local_def_id_from_hir_id(
253+
vdata.ctor_hir_id().unwrap());
254+
let variant = adt_def.variant_with_ctor_id(ctor_did);
255+
256+
if variant.is_field_list_non_exhaustive() &&
257+
ctor_vis == ty::Visibility::Public
258+
{
259+
ctor_vis = ty::Visibility::Restricted(
260+
DefId::local(CRATE_DEF_INDEX));
261+
let attrs = tcx.get_attrs(variant.def_id);
262+
span = attr::find_by_name(&attrs, "non_exhaustive").unwrap().span;
263+
descr = "crate-visible";
264+
}
265+
266+
return (ctor_vis, span, descr);
248267
}
249268
Node::Item(..) => {
250269
let item = match tcx.hir().get_by_hir_id(parent_hir_id) {

src/librustc_resolve/build_reduced_graph.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,14 @@ impl<'a> Resolver<'a> {
588588
let def = Def::Variant(def_id);
589589
self.define(parent, ident, TypeNS, (def, vis, variant.span, expansion));
590590

591+
// If the variant is marked as non_exhaustive then lower the visibility to within the
592+
// crate.
593+
let mut ctor_vis = vis;
594+
let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive");
595+
if has_non_exhaustive && vis == ty::Visibility::Public {
596+
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
597+
}
598+
591599
// Define a constructor name in the value namespace.
592600
// Braced variants, unlike structs, generate unusable names in
593601
// value namespace, they are reserved for possible future use.
@@ -597,7 +605,7 @@ impl<'a> Resolver<'a> {
597605
let ctor_def_id = self.definitions.local_def_id(ctor_node_id);
598606
let ctor_kind = CtorKind::from_ast(&variant.node.data);
599607
let ctor_def = Def::Ctor(ctor_def_id, CtorOf::Variant, ctor_kind);
600-
self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion));
608+
self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, variant.span, expansion));
601609
}
602610

603611
/// Constructs the reduced graph for one foreign item.

src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs

Lines changed: 0 additions & 53 deletions
This file was deleted.

src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)