Skip to main content

rustc_feature/
lib.rs

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.
13
14mod accepted;
15mod builtin_attrs;
16mod removed;
17mod unstable;
18
19#[cfg(test)]
20mod tests;
21
22use std::num::NonZero;
23
24use rustc_span::Symbol;
25
26#[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 {
28    pub 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.
33    pub since: &'static str,
34    issue: Option<NonZero<u32>>,
35}
36
37#[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.
42    Disallow,
43    /// Allow use of unstable features and unstable compiler flags.
44    ///
45    /// Used by default by the nightly channel.
46    Allow,
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.
56    Cheat,
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.
65    AllowSelectedUnstableCompilerFlagsOnly {
66        /// Unstable compiler flags that we are allowed to use, without their `-Z` prefix.
67        allowed_flags: Vec<String>,
68    },
69}
70
71impl 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.
76    pub fn from_environment(krate: Option<&str>) -> Self {
77        Self::from_environment_value(krate, std::env::var("RUSTC_BOOTSTRAP"))
78    }
79
80    /// 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.
83    fn 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.
88        let 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
91        let is_unstable_crate =
92            |var: &str| krate.is_some_and(|name| var.split(',').any(|new_krate| new_krate == name));
93
94        let allow_unstable_flags_prefix = "-allow-unstable-compiler-flags=";
95        if let Ok(val) = env_var_rustc_bootstrap.as_deref() {
96            match val {
97                // Act as stable, but still accept unstable compiler flags required by compiletest
98                val if let Some(flags) = val.strip_prefix(allow_unstable_flags_prefix) => {
99                    return 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        }
110
111        if disable_unstable_features { UnstableFeatures::Disallow } else { UnstableFeatures::Allow }
112    }
113
114    /// Are we allowed to use the given unstable `flag`?
115    /// If it is a `-Z<flag>`, it should be passed without the `-Z` prefix.
116    pub fn allow_unstable_compiler_flag(&self, flag: &str) -> bool {
117        match self {
118            UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
119            UnstableFeatures::AllowSelectedUnstableCompilerFlagsOnly { allowed_flags }
120                if allowed_flags.iter().any(|allowed_flag| allowed_flag == flag) =>
121            {
122                true
123            }
124            UnstableFeatures::Disallow
125            | UnstableFeatures::AllowSelectedUnstableCompilerFlagsOnly { .. } => false,
126        }
127    }
128
129    pub fn is_nightly_build(&self) -> bool {
130        match *self {
131            UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
132            UnstableFeatures::Disallow
133            | UnstableFeatures::AllowSelectedUnstableCompilerFlagsOnly { .. } => false,
134        }
135    }
136}
137
138fn find_lang_feature_issue(feature: Symbol) -> Option<NonZero<u32>> {
139    // Search in all the feature lists.
140    if let Some(f) = UNSTABLE_LANG_FEATURES.iter().find(|f| f.name == feature) {
141        return f.issue;
142    }
143    if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature) {
144        return f.issue;
145    }
146    if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| f.feature.name == feature) {
147        return 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}
151
152const 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.
155    match n {
156        None => None,
157        Some(n) => NonZero::new(n),
158    }
159}
160
161pub enum GateIssue {
162    Language,
163    Library(Option<NonZero<u32>>),
164}
165
166pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u32>> {
167    match issue {
168        GateIssue::Language => find_lang_feature_issue(feature),
169        GateIssue::Library(lib) => lib,
170    }
171}
172
173pub use accepted::ACCEPTED_LANG_FEATURES;
174pub use builtin_attrs::{
175    AttributeStability, BUILTIN_ATTRIBUTE_SET, BUILTIN_ATTRIBUTES, GatedCfg, find_gated_cfg,
176    is_builtin_attr_name,
177};
178pub use removed::REMOVED_LANG_FEATURES;
179pub use unstable::{
180    DEPENDENT_FEATURES, DependentFeature, EnabledLangFeature, EnabledLibFeature, Features,
181    INCOMPATIBLE_FEATURES, TRACK_FEATURE, UNSTABLE_LANG_FEATURES,
182};