rustc_feature/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! # Feature gates
//!
//! This crate declares the set of past and present unstable features in the compiler.
//! Feature gate checking itself is done in `rustc_ast_passes/src/feature_gate.rs`
//! at the moment.
//!
//! Features are enabled in programs via the crate-level attributes of
//! `#![feature(...)]` with a comma-separated list of features.
//!
//! For the purpose of future feature-tracking, once a feature gate is added,
//! even if it is stabilized or removed, *do not remove it*. Instead, move the
//! symbol to the `accepted` or `removed` modules respectively.

// tidy-alphabetical-start
#![allow(internal_features)]
#![doc(rust_logo)]
#![feature(rustdoc_internals)]
#![warn(unreachable_pub)]
// tidy-alphabetical-end

mod accepted;
mod builtin_attrs;
mod removed;
mod unstable;

#[cfg(test)]
mod tests;

use std::num::NonZero;

use rustc_span::symbol::Symbol;

#[derive(Debug, Clone)]
pub struct Feature {
    pub name: Symbol,
    /// For unstable features: the version the feature was added in.
    /// For accepted features: the version the feature got stabilized in.
    /// For removed features we are inconsistent; sometimes this is the
    /// version it got added, sometimes the version it got removed.
    pub since: &'static str,
    issue: Option<NonZero<u32>>,
}

#[derive(Copy, Clone, Debug)]
pub enum Stability {
    Unstable,
    // First argument is tracking issue link; second argument is an optional
    // help message, which defaults to "remove this attribute".
    Deprecated(&'static str, Option<&'static str>),
}

#[derive(Clone, Copy, Debug, Hash)]
pub enum UnstableFeatures {
    /// Disallow use of unstable features, as on beta/stable channels.
    Disallow,
    /// Allow use of unstable features, as on nightly.
    Allow,
    /// Errors are bypassed for bootstrapping. This is required any time
    /// during the build that feature-related lints are set to warn or above
    /// because the build turns on warnings-as-errors and uses lots of unstable
    /// features. As a result, this is always required for building Rust itself.
    Cheat,
}

impl UnstableFeatures {
    /// This takes into account `RUSTC_BOOTSTRAP`.
    ///
    /// If `krate` is [`Some`], then setting `RUSTC_BOOTSTRAP=krate` will enable the nightly
    /// features. Otherwise, only `RUSTC_BOOTSTRAP=1` will work.
    pub fn from_environment(krate: Option<&str>) -> Self {
        // `true` if this is a feature-staged build, i.e., on the beta or stable channel.
        let disable_unstable_features =
            option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some_and(|s| s != "0");
        // Returns whether `krate` should be counted as unstable
        let is_unstable_crate =
            |var: &str| krate.is_some_and(|name| var.split(',').any(|new_krate| new_krate == name));

        let bootstrap = std::env::var("RUSTC_BOOTSTRAP").ok();
        if let Some(val) = bootstrap.as_deref() {
            match val {
                val if val == "1" || is_unstable_crate(val) => return UnstableFeatures::Cheat,
                // Hypnotize ourselves so that we think we are a stable compiler and thus don't
                // allow any unstable features.
                "-1" => return UnstableFeatures::Disallow,
                _ => {}
            }
        }

        if disable_unstable_features { UnstableFeatures::Disallow } else { UnstableFeatures::Allow }
    }

    pub fn is_nightly_build(&self) -> bool {
        match *self {
            UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
            UnstableFeatures::Disallow => false,
        }
    }
}

fn find_lang_feature_issue(feature: Symbol) -> Option<NonZero<u32>> {
    // Search in all the feature lists.
    if let Some(f) = UNSTABLE_LANG_FEATURES.iter().find(|f| f.name == feature) {
        return f.issue;
    }
    if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature) {
        return f.issue;
    }
    if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| f.feature.name == feature) {
        return f.feature.issue;
    }
    panic!("feature `{feature}` is not declared anywhere");
}

const fn to_nonzero(n: Option<u32>) -> Option<NonZero<u32>> {
    // Can be replaced with `n.and_then(NonZero::new)` if that is ever usable
    // in const context. Requires https://github.com/rust-lang/rfcs/pull/2632.
    match n {
        None => None,
        Some(n) => NonZero::new(n),
    }
}

pub enum GateIssue {
    Language,
    Library(Option<NonZero<u32>>),
}

pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u32>> {
    match issue {
        GateIssue::Language => find_lang_feature_issue(feature),
        GateIssue::Library(lib) => lib,
    }
}

pub use accepted::ACCEPTED_LANG_FEATURES;
pub use builtin_attrs::{
    AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,
    BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, deprecated_attributes,
    encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute,
    is_valid_for_get_attr,
};
pub use removed::REMOVED_LANG_FEATURES;
pub use unstable::{
    EnabledLangFeature, EnabledLibFeature, Features, INCOMPATIBLE_FEATURES, UNSTABLE_LANG_FEATURES,
};