]> git.lizzy.rs Git - rust.git/blob - src/librustc_feature/lib.rs
Rollup merge of #66959 - GuillaumeGomez:cfg-duplicates, r=eddyb
[rust.git] / src / librustc_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 `libsyntax/feature_gate/check.rs` at the moment.
5 //!
6 //! Features are enabled in programs via the crate-level attributes of
7 //! `#![feature(...)]` with a comma-separated list of features.
8 //!
9 //! For the purpose of future feature-tracking, once a feature gate is added,
10 //! even if it is stabilized or removed, *do not remove it*. Instead, move the
11 //! symbol to the `accepted` or `removed` modules respectively.
12
13 mod accepted;
14 mod removed;
15 mod active;
16 mod builtin_attrs;
17
18 use std::fmt;
19 use std::num::NonZeroU32;
20 use syntax_pos::{Span, edition::Edition, symbol::Symbol};
21
22 #[derive(Clone, Copy)]
23 pub enum State {
24     Accepted,
25     Active { set: fn(&mut Features, Span) },
26     Removed { reason: Option<&'static str> },
27     Stabilized { reason: Option<&'static str> },
28 }
29
30 impl fmt::Debug for State {
31     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32         match self {
33             State::Accepted { .. } => write!(f, "accepted"),
34             State::Active { .. } => write!(f, "active"),
35             State::Removed { .. } => write!(f, "removed"),
36             State::Stabilized { .. } => write!(f, "stabilized"),
37         }
38     }
39 }
40
41 #[derive(Debug, Clone)]
42 pub struct Feature {
43     pub state: State,
44     pub name: Symbol,
45     pub since: &'static str,
46     issue: Option<u32>,  // FIXME: once #58732 is done make this an Option<NonZeroU32>
47     pub edition: Option<Edition>,
48     description: &'static str,
49 }
50
51 impl Feature {
52     fn issue(&self) -> Option<NonZeroU32> {
53         self.issue.and_then(|i| NonZeroU32::new(i))
54     }
55 }
56
57 #[derive(Copy, Clone, Debug)]
58 pub enum Stability {
59     Unstable,
60     // First argument is tracking issue link; second argument is an optional
61     // help message, which defaults to "remove this attribute".
62     Deprecated(&'static str, Option<&'static str>),
63 }
64
65 #[derive(Clone, Copy, Hash)]
66 pub enum UnstableFeatures {
67     /// Hard errors for unstable features are active, as on beta/stable channels.
68     Disallow,
69     /// Allow features to be activated, as on nightly.
70     Allow,
71     /// Errors are bypassed for bootstrapping. This is required any time
72     /// during the build that feature-related lints are set to warn or above
73     /// because the build turns on warnings-as-errors and uses lots of unstable
74     /// features. As a result, this is always required for building Rust itself.
75     Cheat
76 }
77
78 impl UnstableFeatures {
79     pub fn from_environment() -> UnstableFeatures {
80         // `true` if this is a feature-staged build, i.e., on the beta or stable channel.
81         let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
82         // `true` if we should enable unstable features for bootstrapping.
83         let bootstrap = std::env::var("RUSTC_BOOTSTRAP").is_ok();
84         match (disable_unstable_features, bootstrap) {
85             (_, true) => UnstableFeatures::Cheat,
86             (true, _) => UnstableFeatures::Disallow,
87             (false, _) => UnstableFeatures::Allow
88         }
89     }
90
91     pub fn is_nightly_build(&self) -> bool {
92         match *self {
93             UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
94             UnstableFeatures::Disallow => false,
95         }
96     }
97 }
98
99 fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
100     if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
101         // FIXME (#28244): enforce that active features have issue numbers
102         // assert!(info.issue().is_some())
103         info.issue()
104     } else {
105         // search in Accepted, Removed, or Stable Removed features
106         let found = ACCEPTED_FEATURES
107             .iter()
108             .chain(REMOVED_FEATURES)
109             .chain(STABLE_REMOVED_FEATURES)
110             .find(|t| t.name == feature);
111         match found {
112             Some(found) => found.issue(),
113             None => panic!("feature `{}` is not declared anywhere", feature),
114         }
115     }
116 }
117
118 pub enum GateIssue {
119     Language,
120     Library(Option<NonZeroU32>)
121 }
122
123 pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZeroU32> {
124     match issue {
125         GateIssue::Language => find_lang_feature_issue(feature),
126         GateIssue::Library(lib) => lib,
127     }
128 }
129
130 pub use accepted::ACCEPTED_FEATURES;
131 pub use active::{ACTIVE_FEATURES, Features, INCOMPLETE_FEATURES};
132 pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
133 pub use builtin_attrs::{
134     AttributeGate, AttributeTemplate, AttributeType, find_gated_cfg, GatedCfg,
135     BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
136     deprecated_attributes, is_builtin_attr_name,
137 };