For the how-to steps to add, remove, rename, or stabilize feature gates, see Feature gates.
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.
All feature gate definitions are located in the rustc_feature crate:
rustc_feature/src/unstable.rs via the declare_features! macro. This associates features with issue numbers and tracking metadata.rustc_feature/src/accepted.rs.rustc_feature/src/removed.rs.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.
Before AST validation or expansion, rustc collects crate-level #![feature(...)] attributes to build the active Features set.
rustc_expand/src/config.rs in features.#![feature] entry is classified against the unstable, accepted, and removed tables: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.-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).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.rustc_parse/src/parser/* when it encounters syntax that requires a gate (e.g., async for, yield, experimental patterns).The central logic lives in rustc_ast_passes/src/feature_gate.rs, primarily in check_crate and its AST visitor.
check_cratecheck_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 compiler mode for the next trait solver.GatedSpans recorded during parsing (see Checking GatedSpans).GatedSpanscheck_crate iterates over sess.psess.gated_spans:
gate_all! macro emits diagnostics for each gated span if the feature is not enabled.yield can be allowed by coroutines or gen_blocks).box_patterns, try_blocks) may use a separate path that emits future-incompatibility warnings instead of hard errors.A PostExpansionVisitor walks the expanded AST to check constructs that are easier to validate after expansion.
gate!, gate_alt!, gate_multi!) to check:span.allows_unstable permit it (for internal compiler macros)?trait_alias, decl_macro, extern types, and various impl Trait forms.cfgBeyond syntax, rustc also gates attributes and cfg options.
rustc_ast_passes::check_attribute inspects attributes against BUILTIN_ATTRIBUTE_MAP.AttributeGate::Gated and the feature isn’t enabled, feature_err is emitted.cfg optionsrustc_attr_parsing/src/attributes/cfg.rs defines gate_cfg and uses rustc_feature::find_gated_cfg to reject gated cfgs.gate_cfg respects Span::allows_unstable, allowing internal compiler macros to bypass cfg gates when marked with #[allow_internal_unstable].rustc_feature/src/builtin_attrs.rs.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.