From e6b4102fa654f019e46c2fd959460e9f2c0330b3 Mon Sep 17 00:00:00 2001 From: Alyssa Haroldsen Date: Fri, 8 May 2026 15:51:51 -0700 Subject: [PATCH] Add experimental `unnamed_enum_variants` feature gate --- compiler/rustc_ast_lowering/src/item.rs | 6 ++++++ compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_parse/src/parser/item.rs | 11 ++++++++-- compiler/rustc_span/src/symbol.rs | 1 + tests/ui/README.md | 4 ++++ .../feature-gate-unnamed-enum-variants.rs | 13 ++++++++++++ .../feature-gate-unnamed-enum-variants.stderr | 21 +++++++++++++++++++ .../ui/unnamed-enum-variants/unimplemented.rs | 8 +++++++ .../unimplemented.stderr | 8 +++++++ 10 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-unnamed-enum-variants.rs create mode 100644 tests/ui/feature-gates/feature-gate-unnamed-enum-variants.stderr create mode 100644 tests/ui/unnamed-enum-variants/unimplemented.rs create mode 100644 tests/ui/unnamed-enum-variants/unimplemented.stderr diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 70f55d67c7a16..8f7459c046946 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -857,6 +857,12 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_variant(&mut self, item_kind: &ItemKind, v: &Variant) -> hir::Variant<'hir> { + if v.ident.name == kw::Underscore && self.tcx.features().unnamed_enum_variants() { + // FIXME(#156628): lower unnamed enum variants to HIR. + self.dcx() + .struct_span_fatal(v.span, "unnamed enum variants are not yet implemented") + .emit() + } let hir_id = self.lower_node_id(v.id); self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant); hir::Variant { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 1b3ce2427c3c7..e428f79fa139a 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -511,6 +511,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(return_type_notation, "return type notation is experimental"); gate_all!(super_let, "`super let` is experimental"); gate_all!(try_blocks_heterogeneous, "`try bikeshed` expression is experimental"); + gate_all!(unnamed_enum_variants, "unnamed enum variants are experimental"); gate_all!(unsafe_binders, "unsafe binder types are experimental"); gate_all!(unsafe_fields, "`unsafe` fields are experimental"); gate_all!(view_types, "view types are experimental"); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 388482209cf9e..3e4ac157eee0f 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -750,6 +750,8 @@ declare_features! ( /// Allows creation of instances of a struct by moving fields that have /// not changed from prior instances of the same struct (RFC #2528) (unstable, type_changing_struct_update, "1.58.0", Some(86555)), + /// Allows using `_ = ` enum variants. + (incomplete, unnamed_enum_variants, "CURRENT_RUSTC_VERSION", Some(156628)), /// Allows using `unsafe<'a> &'a T` unsafe binder types. (incomplete, unsafe_binders, "1.85.0", Some(130516)), /// Allows declaring fields `unsafe`. diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 3f6429c6a60f0..5762b889c6688 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1915,6 +1915,10 @@ impl<'a> Parser<'a> { None }; + let span = vlo.to(this.prev_token.span); + if ident.name == kw::Underscore { + this.psess.gated_spans.gate(sym::unnamed_enum_variants, span); + } let vr = ast::Variant { ident, vis, @@ -1922,7 +1926,7 @@ impl<'a> Parser<'a> { attrs: variant_attrs, data: struct_def, disr_expr, - span: vlo.to(this.prev_token.span), + span, is_placeholder: false, }; @@ -2382,7 +2386,10 @@ impl<'a> Parser<'a> { /// for better diagnostics and suggestions. fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> { let (ident, is_raw) = self.ident_or_err(true)?; - if is_raw == IdentIsRaw::No && ident.is_reserved() { + if is_raw == IdentIsRaw::No + && ident.is_reserved() + && !(ident.name == kw::Underscore && adt_ty == "enum") + { let snapshot = self.create_snapshot_for_diagnostic(); let err = if self.check_fn_front_matter(false, Case::Sensitive) { let inherited_vis = diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7263680c302f1..d4341ad8ba7b6 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2171,6 +2171,7 @@ symbols! { unix, unlikely, unmarked_api, + unnamed_enum_variants, unnamed_fields, unpin, unqualified_local_imports, diff --git a/tests/ui/README.md b/tests/ui/README.md index f76cd507056fe..00afc98a0b55a 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -1501,6 +1501,10 @@ See [Uninhabited | Reference](https://doc.rust-lang.org/reference/glossary.html? See [Unions | Reference](https://doc.rust-lang.org/reference/items/unions.html). +## `tests/ui/unnamed-enum-variants`: `_ = ` in an `enum` + +See [Tracking Issue for Unnamed Enum Variants (Open Enums) #156628](https://github.com/rust-lang/rust/issues/156628) + ## `tests/ui/unop/`: Unary operators `-`, `*` and `!` Tests the three unary operators for negating, dereferencing and inverting, across different contexts. diff --git a/tests/ui/feature-gates/feature-gate-unnamed-enum-variants.rs b/tests/ui/feature-gates/feature-gate-unnamed-enum-variants.rs new file mode 100644 index 0000000000000..de497076a4b14 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unnamed-enum-variants.rs @@ -0,0 +1,13 @@ +#[repr(u8)] +enum Foo { + X = 0, + _ = 1, //~ ERROR unnamed enum variants are experimental +} + +// This should not parse as an unnamed enum variant. +#[cfg(false)] +struct Foo { + _: i32, //~ ERROR expected identifier, found reserved identifier `_` +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-unnamed-enum-variants.stderr b/tests/ui/feature-gates/feature-gate-unnamed-enum-variants.stderr new file mode 100644 index 0000000000000..e24b9e98ff8dc --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unnamed-enum-variants.stderr @@ -0,0 +1,21 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/feature-gate-unnamed-enum-variants.rs:10:5 + | +LL | struct Foo { + | --- while parsing this struct +LL | _: i32, + | ^ expected identifier, found reserved identifier + +error[E0658]: unnamed enum variants are experimental + --> $DIR/feature-gate-unnamed-enum-variants.rs:4:5 + | +LL | _ = 1, + | ^^^^^ + | + = note: see issue #156628 for more information + = help: add `#![feature(unnamed_enum_variants)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/unnamed-enum-variants/unimplemented.rs b/tests/ui/unnamed-enum-variants/unimplemented.rs new file mode 100644 index 0000000000000..afa01fb67d67b --- /dev/null +++ b/tests/ui/unnamed-enum-variants/unimplemented.rs @@ -0,0 +1,8 @@ +//@ compile-flags: --crate-type=lib +#![allow(incomplete_features)] +#![feature(unnamed_enum_variants)] + +#[repr(u8)] +enum Foo { + _ = 1, //~ ERROR unnamed enum variants are not yet implemented +} diff --git a/tests/ui/unnamed-enum-variants/unimplemented.stderr b/tests/ui/unnamed-enum-variants/unimplemented.stderr new file mode 100644 index 0000000000000..c1d662a0b501b --- /dev/null +++ b/tests/ui/unnamed-enum-variants/unimplemented.stderr @@ -0,0 +1,8 @@ +error: unnamed enum variants are not yet implemented + --> $DIR/unimplemented.rs:7:5 + | +LL | _ = 1, + | ^^^^^ + +error: aborting due to 1 previous error +