1//! # Feature gates
2//!
3//! This crate declares the set of past and present unstable features in the compiler.
4//! Feature gate checking itself is done in `rustc_ast_passes/src/feature_gate.rs`
5//! at the moment.
6//!
7//! Features are enabled in programs via the crate-level attributes of
8//! `#![feature(...)]` with a comma-separated list of features.
9//!
10//! For the purpose of future feature-tracking, once a feature gate is added,
11//! even if it is stabilized or removed, *do not remove it*. Instead, move the
12//! symbol to the `accepted` or `removed` modules respectively.
1314mod accepted;
15mod builtin_attrs;
16mod removed;
17mod unstable;
1819#[cfg(test)]
20mod tests;
2122use std::num::NonZero;
2324use rustc_span::Symbol;
2526#[derive(#[automatically_derived]impl ::core::fmt::Debug for Feature {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"Feature name since issue", &self.name, &self.since, &&self.issue)
}
}Debug, #[automatically_derived]impl ::core::clone::Clone for Feature {
#[inline]
fn clone(&self) -> Self {
Feature {
name: ::core::clone::Clone::clone(&self.name),
since: ::core::clone::Clone::clone(&self.since),
issue: ::core::clone::Clone::clone(&self.issue),
}
}
}Clone)]
27pub struct Feature {
28pub name: Symbol,
29/// For unstable features: the version the feature was added in.
30 /// For accepted features: the version the feature got stabilized in.
31 /// For removed features we are inconsistent; sometimes this is the
32 /// version it got added, sometimes the version it got removed.
33pub since: &'static str,
34 issue: Option<NonZero<u32>>,
35}
3637#[derive(#[automatically_derived]impl ::core::clone::Clone for UnstableFeatures {
#[inline]
fn clone(&self) -> Self {
match self {
Self::Disallow => UnstableFeatures::Disallow,
Self::Allow => UnstableFeatures::Allow,
Self::Cheat => UnstableFeatures::Cheat,
Self::AllowSelectedUnstableCompilerFlagsOnly {
allowed_flags: __self_0 } =>
UnstableFeatures::AllowSelectedUnstableCompilerFlagsOnly {
allowed_flags: ::core::clone::Clone::clone(__self_0),
},
}
}
}Clone, #[automatically_derived]impl ::core::fmt::Debug for UnstableFeatures {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::Disallow =>
::core::fmt::Formatter::write_str(f, "Disallow"),
Self::Allow => ::core::fmt::Formatter::write_str(f, "Allow"),
Self::Cheat => ::core::fmt::Formatter::write_str(f, "Cheat"),
Self::AllowSelectedUnstableCompilerFlagsOnly {
allowed_flags: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"AllowSelectedUnstableCompilerFlagsOnly allowed_flags",
&__self_0),
}
}
}Debug, #[automatically_derived]impl ::core::hash::Hash for UnstableFeatures {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
state);
match self {
Self::AllowSelectedUnstableCompilerFlagsOnly {
allowed_flags: __self_0 } =>
::core::hash::Hash::hash(__self_0, state),
_ => {}
}
}
}Hash, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
UnstableFeatures {
}
#[automatically_derived]impl ::core::cmp::PartialEq for UnstableFeatures {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other) &&
match (self, other) {
(Self::AllowSelectedUnstableCompilerFlagsOnly {
allowed_flags: __self_0 },
Self::AllowSelectedUnstableCompilerFlagsOnly {
allowed_flags: __arg1_0 }) => __self_0 == __arg1_0,
_ => true,
}
}
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for UnstableFeatures {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Vec<String>>;
}
}Eq)]
38pub enum UnstableFeatures {
39/// Disallow use of unstable features and unstable compiler flags.
40 ///
41 /// Used by default by beta/stable channels.
42Disallow,
43/// Allow use of unstable features and unstable compiler flags.
44 ///
45 /// Used by default by the nightly channel.
46Allow,
47/// Allow use of unstable features and unstable compiler flags, even if it is not the default
48 /// behavior.
49 ///
50 /// Can be used to make a beta/stable channel act like a nightly channel.
51 ///
52 /// Errors are bypassed for bootstrapping. This is required any time
53 /// during the build that feature-related lints are set to warn or above
54 /// because the build turns on warnings-as-errors and uses lots of unstable
55 /// features. As a result, this is always required for building Rust itself.
56Cheat,
57/// Allow the use of selected *unstable compiler flags*, but disallow the use of
58 /// *unstable language features*.
59 ///
60 /// **This mode is designed only for internal testing of rustc.**
61 ///
62 /// Specifically, we need it when we want to test how rustc behaves on the stable channel,
63 /// but at the same time we need to be able to pass it some unstable `-Z` compiler flags
64 /// required for the testing infrastructure itself to work.
65AllowSelectedUnstableCompilerFlagsOnly {
66/// Unstable compiler flags that we are allowed to use, without their `-Z` prefix.
67allowed_flags: Vec<String>,
68 },
69}
7071impl UnstableFeatures {
72/// This takes into account `RUSTC_BOOTSTRAP`.
73 ///
74 /// If `krate` is [`Some`], then setting `RUSTC_BOOTSTRAP=krate` will enable the nightly
75 /// features. Otherwise, only `RUSTC_BOOTSTRAP=1` will work.
76pub fn from_environment(krate: Option<&str>) -> Self {
77Self::from_environment_value(krate, std::env::var("RUSTC_BOOTSTRAP"))
78 }
7980/// Avoid unsafe `std::env::set_var()` by allowing tests to inject
81 /// `std::env::var("RUSTC_BOOTSTRAP")` with the `env_var_rustc_bootstrap`
82 /// arg.
83fn from_environment_value(
84 krate: Option<&str>,
85 env_var_rustc_bootstrap: Result<String, std::env::VarError>,
86 ) -> Self {
87// `true` if this is a feature-staged build, i.e., on the beta or stable channel.
88let disable_unstable_features =
89::core::option::Option::None::<&'static str>option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some_and(|s| s != "0");
90// Returns whether `krate` should be counted as unstable
91let is_unstable_crate =
92 |var: &str| krate.is_some_and(|name| var.split(',').any(|new_krate| new_krate == name));
9394let allow_unstable_flags_prefix = "-allow-unstable-compiler-flags=";
95if let Ok(val) = env_var_rustc_bootstrap.as_deref() {
96match val {
97// Act as stable, but still accept unstable compiler flags required by compiletest
98val if let Some(flags) = val.strip_prefix(allow_unstable_flags_prefix) => {
99return UnstableFeatures::AllowSelectedUnstableCompilerFlagsOnly {
100 allowed_flags: flags.split(",").map(|s| s.trim().to_string()).collect(),
101 };
102 }
103 val if val == "1" || is_unstable_crate(val) => return UnstableFeatures::Cheat,
104// Hypnotize ourselves so that we think we are a stable compiler and thus don't
105 // allow any unstable features.
106"-1" => return UnstableFeatures::Disallow,
107_ => {}
108 }
109 }
110111if disable_unstable_features { UnstableFeatures::Disallow } else { UnstableFeatures::Allow }
112 }
113114/// Are we allowed to use the given unstable `flag`?
115 /// If it is a `-Z<flag>`, it should be passed without the `-Z` prefix.
116pub fn allow_unstable_compiler_flag(&self, flag: &str) -> bool {
117match self {
118 UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
119 UnstableFeatures::AllowSelectedUnstableCompilerFlagsOnly { allowed_flags }
120if allowed_flags.iter().any(|allowed_flag| allowed_flag == flag) =>
121 {
122true
123}
124 UnstableFeatures::Disallow125 | UnstableFeatures::AllowSelectedUnstableCompilerFlagsOnly { .. } => false,
126 }
127 }
128129pub fn is_nightly_build(&self) -> bool {
130match *self {
131 UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
132 UnstableFeatures::Disallow133 | UnstableFeatures::AllowSelectedUnstableCompilerFlagsOnly { .. } => false,
134 }
135 }
136}
137138fn find_lang_feature_issue(feature: Symbol) -> Option<NonZero<u32>> {
139// Search in all the feature lists.
140if let Some(f) = UNSTABLE_LANG_FEATURES.iter().find(|f| f.name == feature) {
141return f.issue;
142 }
143if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature) {
144return f.issue;
145 }
146if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| f.feature.name == feature) {
147return f.feature.issue;
148 }
149{
::core::panicking::panic_fmt(format_args!("feature `{0}` is not declared anywhere",
feature));
};panic!("feature `{feature}` is not declared anywhere");
150}
151152const fn to_nonzero(n: Option<u32>) -> Option<NonZero<u32>> {
153// Can be replaced with `n.and_then(NonZero::new)` if that is ever usable
154 // in const context. Requires https://github.com/rust-lang/rfcs/pull/2632.
155match n {
156None => None,
157Some(n) => NonZero::new(n),
158 }
159}
160161pub enum GateIssue {
162 Language,
163 Library(Option<NonZero<u32>>),
164}
165166pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u32>> {
167match issue {
168 GateIssue::Language => find_lang_feature_issue(feature),
169 GateIssue::Library(lib) => lib,
170 }
171}
172173pub use accepted::ACCEPTED_LANG_FEATURES;
174pub use builtin_attrs::{
175AttributeStability, BUILTIN_ATTRIBUTE_SET, BUILTIN_ATTRIBUTES, GatedCfg, find_gated_cfg,
176is_builtin_attr_name,
177};
178pub use removed::REMOVED_LANG_FEATURES;
179pub use unstable::{
180DEPENDENT_FEATURES, DependentFeature, EnabledLangFeature, EnabledLibFeature, Features,
181INCOMPATIBLE_FEATURES, TRACK_FEATURE, UNSTABLE_LANG_FEATURES,
182};