From 9aba9679a9b5ec8e79a973c25db69ba4972032df Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sat, 31 Jan 2026 06:46:57 +0900 Subject: [PATCH 1/4] Document feature gate checking --- src/feature-gate-ck.md | 132 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/src/feature-gate-ck.md b/src/feature-gate-ck.md index c17747a11b..c840118075 100644 --- a/src/feature-gate-ck.md +++ b/src/feature-gate-ck.md @@ -1,3 +1,133 @@ # Feature Gate Checking -**TODO**: this chapter [#1158](https://github.com/rust-lang/rustc-dev-guide/issues/1158) +Feature gates prevent usage of unstable language and library features without a +nightly-only `#![feature(...)]` opt-in. This chapter documents the implementation +of feature gating: where gates are defined, how they are enabled, and how usage +is verified. + +## Feature Definitions + +All feature gate definitions are located in the `rustc_feature` crate: + +- **Unstable features** are declared in [`rustc_feature/src/unstable.rs`] via + the `declare_features!` macro. This associates features with issue numbers and + tracking metadata. +- **Accepted features** (stabilized) are listed in [`rustc_feature/src/accepted.rs`]. +- **Removed features** (explicitly disallowed) are listed in [`rustc_feature/src/removed.rs`]. +- **Gated built-in attributes and cfgs** are declared in [`rustc_feature/src/builtin_attrs.rs`]. + +The [`rustc_feature::Features`] type represents the **active feature set** for a +crate. Helpers like `enabled`, `incomplete`, and `internal` are used during +compilation to check status. + +## Collecting Features + +Before AST validation or expansion, `rustc` collects crate-level +`#![feature(...)]` attributes to build the active `Features` set. + +- The collection happens in [`rustc_expand/src/config.rs`] in [`features`]. +- Each `#![feature]` entry is classified against the `unstable`, `accepted`, and + `removed` tables: + - **Removed** features cause an immediate error. + - **Accepted** features are recorded but do not require nightly. On + stable/beta they trigger the "already stabilized" diagnostic. + - **Unstable** features are recorded as enabled. + - Unknown features are treated as **library features** and validated later. +- With `-Z allow-features=...`, any **unstable** or **unknown** feature + not in the allowlist is rejected. +- [`RUSTC_BOOTSTRAP`] feeds into `UnstableFeatures::from_environment`. This + variable controls whether the compiler is treated as "nightly", allowing + feature gates to be bypassed during bootstrapping or explicitly disabled (`-1`). + +## Parser Gating + +Some syntax is detected and gated during parsing. The parser records spans for +later checking to keep diagnostics consistent and deferred until after parsing. + +- [`rustc_session/src/parse.rs`] defines [`GatedSpans`] and the `gate` method. +- The parser uses it in [`rustc_parse/src/parser/*`] when it encounters + syntax that requires a gate (e.g., `async for`, `yield`, experimental patterns). + +## Checking Pass + +The central logic lives in [`rustc_ast_passes/src/feature_gate.rs`], primarily +in `check_crate` and its AST visitor. + +### `check_crate` + +`check_crate` performs high-level validation: + +- `maybe_stage_features`: Rejects `#![feature]` on stable/beta. +- `check_incompatible_features`: Ensures incompatible feature combinations + (declared in `rustc_feature::INCOMPATIBLE_FEATURES`) are not used together. +- `check_new_solver_banned_features`: Bans features incompatible with + certain compiler modes (e.g., the next trait solver). +- **Parser-gated spans**: Processes the `GatedSpans` recorded during parsing. + +### AST Visitor + +A `PostExpansionVisitor` walks the expanded AST to check constructs that are +easier to validate after expansion. + +- The visitor uses helper macros (`gate!`, `gate_alt!`, `gate_multi!`) to check: + 1. Is the feature enabled? + 2. Does `span.allows_unstable` permit it (for internal compiler macros)? +- Examples include `trait_alias`, `decl_macro`, `extern types`, and various + `impl Trait` forms. + +### Checking `GatedSpans` + +`check_crate` iterates over `sess.psess.gated_spans`: + +- The `gate_all!` macro emits diagnostics for each gated span if the feature is + not enabled. +- Some gates have extra logic (e.g., `yield` can be allowed by `coroutines` or + `gen_blocks`). +- Legacy gates (e.g., `box_patterns`, `try_blocks`) may use a separate path that + emits future-incompatibility warnings instead of hard errors. + +## Attributes and `cfg` + +Beyond syntax, rustc also gates attributes and `cfg` options. + +### Built-in attributes + +- [`rustc_ast_passes::check_attribute`] inspects attributes against + `BUILTIN_ATTRIBUTE_MAP`. +- If the attribute is `AttributeGate::Gated` and the feature isn’t enabled, + `feature_err` is emitted. + +### `cfg` options + +- [`rustc_attr_parsing/src/attributes/cfg.rs`] defines + `find_gated_cfg`/`gate_cfg` to reject gated `cfg`s. +- `gate_cfg` respects `Span::allows_unstable`, allowing internal compiler + macros to bypass `cfg` gates when marked with `#[allow_internal_unstable]`. +- The gated cfg list is defined in [`rustc_feature/src/builtin_attrs.rs`]. + +## Diagnostics + +Diagnostic helpers are located in [`rustc_session/src/parse.rs`]. + +- `feature_err` and `feature_warn` emit standardized diagnostics, attaching the + tracking issue number where possible. +- `Span::allows_unstable` in [`rustc_span/src/lib.rs`] checks if a span originates + from a macro marked with `#[allow_internal_unstable]`. This allows internal + macros to use unstable features on stable channels while enforcing gates for + user code. + +[`rustc_feature/src/unstable.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_feature/src/unstable.rs +[`rustc_feature/src/removed.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_feature/src/removed.rs +[`rustc_feature/src/accepted.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_feature/src/accepted.rs +[`rustc_feature/src/builtin_attrs.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_feature/src/builtin_attrs.rs +[`rustc_feature::Features`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_feature/struct.Features.html +[`rustc_expand/src/config.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_expand/src/config.rs +[`features`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/config/fn.features.html +[`RUSTC_BOOTSTRAP`]: https://doc.rust-lang.org/beta/unstable-book/compiler-environment-variables/RUSTC_BOOTSTRAP.html +[`rustc_session/src/parse.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_session/src/parse.rs +[`GatedSpans`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/struct.GatedSpans.html +[`rustc_ast_passes/src/feature_gate.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_ast_passes/src/feature_gate.rs +[`rustc_parse/src/parser/*`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/index.html +[`rustc_ast_passes::check_attribute`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_passes/feature_gate/fn.check_attribute.html +[`rustc_attr_parsing/src/attributes/cfg.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_attr_parsing/src/attributes/cfg.rs +[`rustc_span/src/lib.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_span/src/lib.rs From d583667add2c94b23a047b9bf493ebccf7b8ad0d Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 3 Feb 2026 14:24:48 +0900 Subject: [PATCH 2/4] Clarify description of new solver banned features Co-authored-by: Tshepang Mbambo --- src/feature-gate-ck.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/feature-gate-ck.md b/src/feature-gate-ck.md index c840118075..8a93fbc756 100644 --- a/src/feature-gate-ck.md +++ b/src/feature-gate-ck.md @@ -61,7 +61,7 @@ in `check_crate` and its AST visitor. - `check_incompatible_features`: Ensures incompatible feature combinations (declared in `rustc_feature::INCOMPATIBLE_FEATURES`) are not used together. - `check_new_solver_banned_features`: Bans features incompatible with - certain compiler modes (e.g., the next trait solver). + compiler mode for the next trait solver. - **Parser-gated spans**: Processes the `GatedSpans` recorded during parsing. ### AST Visitor From fc22e61f45d32186a1b65a0416a2de5eec25eeb4 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 3 Feb 2026 14:36:17 +0900 Subject: [PATCH 3/4] Rename `feature-gate-ck.md` to `feature-gate-check.md` --- src/SUMMARY.md | 2 +- src/{feature-gate-ck.md => feature-gate-check.md} | 0 src/syntax-intro.md | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{feature-gate-ck.md => feature-gate-check.md} (100%) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 5342c54607..22f4da50b6 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -124,7 +124,7 @@ - [`#[test]` implementation](./test-implementation.md) - [Panic implementation](./panic-implementation.md) - [AST validation](./ast-validation.md) - - [Feature gate checking](./feature-gate-ck.md) + - [Feature gate checking](./feature-gate-check.md) - [Lang Items](./lang-items.md) - [The HIR (High-level IR)](./hir.md) - [Lowering AST to HIR](./hir/lowering.md) diff --git a/src/feature-gate-ck.md b/src/feature-gate-check.md similarity index 100% rename from src/feature-gate-ck.md rename to src/feature-gate-check.md diff --git a/src/syntax-intro.md b/src/syntax-intro.md index 0f5a91ee50..a5a8bab149 100644 --- a/src/syntax-intro.md +++ b/src/syntax-intro.md @@ -13,7 +13,7 @@ And parsing requires macro expansion, which in turn may require parsing the outp [AST]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html [macro expansion]: ./macro-expansion.md -[feature-gate checking]: ./feature-gate-ck.md +[feature-gate checking]: ./feature-gate-check.md [lexing, parsing]: ./the-parser.md [name resolution]: ./name-resolution.md [validation]: ./ast-validation.md From 5c783adf5321921377204b7936d17cf563313ff7 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 3 Feb 2026 14:41:54 +0900 Subject: [PATCH 4/4] Clarify and reorganize feature-gate-check doc --- src/feature-gate-check.md | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/feature-gate-check.md b/src/feature-gate-check.md index 8a93fbc756..591231c022 100644 --- a/src/feature-gate-check.md +++ b/src/feature-gate-check.md @@ -5,6 +5,8 @@ nightly-only `#![feature(...)]` opt-in. This chapter documents the implementatio of feature gating: where gates are defined, how they are enabled, and how usage is verified. + + ## Feature Definitions All feature gate definitions are located in the `rustc_feature` crate: @@ -30,7 +32,10 @@ Before AST validation or expansion, `rustc` collects crate-level `removed` tables: - **Removed** features cause an immediate error. - **Accepted** features are recorded but do not require nightly. On - stable/beta they trigger the "already stabilized" diagnostic. + stable/beta, `maybe_stage_features` in + [`rustc_ast_passes/src/feature_gate.rs`] emits the non-nightly + diagnostic and lists stable features, which is where the "already + stabilized" messaging comes from. - **Unstable** features are recorded as enabled. - Unknown features are treated as **library features** and validated later. - With `-Z allow-features=...`, any **unstable** or **unknown** feature @@ -62,18 +67,8 @@ in `check_crate` and its AST visitor. (declared in `rustc_feature::INCOMPATIBLE_FEATURES`) are not used together. - `check_new_solver_banned_features`: Bans features incompatible with compiler mode for the next trait solver. -- **Parser-gated spans**: Processes the `GatedSpans` recorded during parsing. - -### AST Visitor - -A `PostExpansionVisitor` walks the expanded AST to check constructs that are -easier to validate after expansion. - -- The visitor uses helper macros (`gate!`, `gate_alt!`, `gate_multi!`) to check: - 1. Is the feature enabled? - 2. Does `span.allows_unstable` permit it (for internal compiler macros)? -- Examples include `trait_alias`, `decl_macro`, `extern types`, and various - `impl Trait` forms. +- **Parser-gated spans**: Processes the `GatedSpans` recorded during parsing + (see [Checking `GatedSpans`](#checking-gatedspans)). ### Checking `GatedSpans` @@ -86,6 +81,17 @@ easier to validate after expansion. - Legacy gates (e.g., `box_patterns`, `try_blocks`) may use a separate path that emits future-incompatibility warnings instead of hard errors. +### AST Visitor + +A `PostExpansionVisitor` walks the expanded AST to check constructs that are +easier to validate after expansion. + +- The visitor uses helper macros (`gate!`, `gate_alt!`, `gate_multi!`) to check: + 1. Is the feature enabled? + 2. Does `span.allows_unstable` permit it (for internal compiler macros)? +- Examples include `trait_alias`, `decl_macro`, `extern types`, and various + `impl Trait` forms. + ## Attributes and `cfg` Beyond syntax, rustc also gates attributes and `cfg` options. @@ -99,8 +105,8 @@ Beyond syntax, rustc also gates attributes and `cfg` options. ### `cfg` options -- [`rustc_attr_parsing/src/attributes/cfg.rs`] defines - `find_gated_cfg`/`gate_cfg` to reject gated `cfg`s. +- [`rustc_attr_parsing/src/attributes/cfg.rs`] defines `gate_cfg` and uses + [`rustc_feature::find_gated_cfg`] to reject gated `cfg`s. - `gate_cfg` respects `Span::allows_unstable`, allowing internal compiler macros to bypass `cfg` gates when marked with `#[allow_internal_unstable]`. - The gated cfg list is defined in [`rustc_feature/src/builtin_attrs.rs`]. @@ -130,4 +136,5 @@ Diagnostic helpers are located in [`rustc_session/src/parse.rs`]. [`rustc_parse/src/parser/*`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/index.html [`rustc_ast_passes::check_attribute`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_passes/feature_gate/fn.check_attribute.html [`rustc_attr_parsing/src/attributes/cfg.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_attr_parsing/src/attributes/cfg.rs +[`rustc_feature::find_gated_cfg`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_feature/fn.find_gated_cfg.html [`rustc_span/src/lib.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_span/src/lib.rs