rustc_hir/
stability.rs

1use std::num::NonZero;
2
3use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
4use rustc_span::{ErrorGuaranteed, Symbol, sym};
5
6use crate::RustcVersion;
7use crate::attrs::PrintAttribute;
8
9/// The version placeholder that recently stabilized features contain inside the
10/// `since` field of the `#[stable]` attribute.
11///
12/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591).
13pub const VERSION_PLACEHOLDER: &str = concat!("CURRENT_RUSTC_VERSIO", "N");
14// Note that the `concat!` macro above prevents `src/tools/replace-version-placeholder` from
15// replacing the constant with the current version. Hardcoding the tool to skip this file doesn't
16// work as the file can (and at some point will) be moved around.
17//
18// Turning the `concat!` macro into a string literal will make Pietro cry. That'd be sad :(
19
20/// Represents the following attributes:
21///
22/// - `#[stable]`
23/// - `#[unstable]`
24#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
25#[derive(HashStable_Generic, PrintAttribute)]
26pub struct Stability {
27    pub level: StabilityLevel,
28    pub feature: Symbol,
29}
30
31impl Stability {
32    pub fn is_unstable(&self) -> bool {
33        self.level.is_unstable()
34    }
35
36    pub fn is_stable(&self) -> bool {
37        self.level.is_stable()
38    }
39
40    pub fn stable_since(&self) -> Option<StableSince> {
41        self.level.stable_since()
42    }
43}
44
45/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
46#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
47#[derive(HashStable_Generic, PrintAttribute)]
48pub struct ConstStability {
49    pub level: StabilityLevel,
50    pub feature: Symbol,
51    /// whether the function has a `#[rustc_promotable]` attribute
52    pub promotable: bool,
53    /// This is true iff the `const_stable_indirect` attribute is present.
54    pub const_stable_indirect: bool,
55}
56
57impl ConstStability {
58    pub fn from_partial(
59        PartialConstStability { level, feature, promotable }: PartialConstStability,
60        const_stable_indirect: bool,
61    ) -> Self {
62        Self { const_stable_indirect, level, feature, promotable }
63    }
64
65    /// The stability assigned to unmarked items when -Zforce-unstable-if-unmarked is set.
66    pub fn unmarked(const_stable_indirect: bool, regular_stab: Stability) -> Self {
67        Self {
68            feature: regular_stab.feature,
69            promotable: false,
70            level: regular_stab.level,
71            const_stable_indirect,
72        }
73    }
74
75    pub fn is_const_unstable(&self) -> bool {
76        self.level.is_unstable()
77    }
78
79    pub fn is_const_stable(&self) -> bool {
80        self.level.is_stable()
81    }
82}
83
84/// Excludes `const_stable_indirect`. This is necessary because when `-Zforce-unstable-if-unmarked`
85/// is set, we need to encode standalone `#[rustc_const_stable_indirect]` attributes
86#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
87#[derive(HashStable_Generic, PrintAttribute)]
88pub struct PartialConstStability {
89    pub level: StabilityLevel,
90    pub feature: Symbol,
91    /// whether the function has a `#[rustc_promotable]` attribute
92    pub promotable: bool,
93}
94
95impl PartialConstStability {
96    pub fn is_const_unstable(&self) -> bool {
97        self.level.is_unstable()
98    }
99
100    pub fn is_const_stable(&self) -> bool {
101        self.level.is_stable()
102    }
103}
104
105/// The available stability levels.
106#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
107#[derive(HashStable_Generic, PrintAttribute)]
108pub enum StabilityLevel {
109    /// `#[unstable]`
110    Unstable {
111        /// Reason for the current stability level.
112        reason: UnstableReason,
113        /// Relevant `rust-lang/rust` issue.
114        issue: Option<NonZero<u32>>,
115        is_soft: bool,
116        /// If part of a feature is stabilized and a new feature is added for the remaining parts,
117        /// then the `implied_by` attribute is used to indicate which now-stable feature previously
118        /// contained an item.
119        ///
120        /// ```pseudo-Rust
121        /// #[unstable(feature = "foo", issue = "...")]
122        /// fn foo() {}
123        /// #[unstable(feature = "foo", issue = "...")]
124        /// fn foobar() {}
125        /// ```
126        ///
127        /// ...becomes...
128        ///
129        /// ```pseudo-Rust
130        /// #[stable(feature = "foo", since = "1.XX.X")]
131        /// fn foo() {}
132        /// #[unstable(feature = "foobar", issue = "...", implied_by = "foo")]
133        /// fn foobar() {}
134        /// ```
135        implied_by: Option<Symbol>,
136        old_name: Option<Symbol>,
137    },
138    /// `#[stable]`
139    Stable {
140        /// Rust release which stabilized this feature.
141        since: StableSince,
142        /// This is `Some` if this item allowed to be referred to on stable via unstable modules;
143        /// the `Symbol` is the deprecation message printed in that case.
144        allowed_through_unstable_modules: Option<Symbol>,
145    },
146}
147
148/// Rust release in which a feature is stabilized.
149#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)]
150#[derive(HashStable_Generic, PrintAttribute)]
151pub enum StableSince {
152    /// also stores the original symbol for printing
153    Version(RustcVersion),
154    /// Stabilized in the upcoming version, whatever number that is.
155    Current,
156    /// Failed to parse a stabilization version.
157    Err(ErrorGuaranteed),
158}
159
160impl StabilityLevel {
161    pub fn is_unstable(&self) -> bool {
162        matches!(self, StabilityLevel::Unstable { .. })
163    }
164    pub fn is_stable(&self) -> bool {
165        matches!(self, StabilityLevel::Stable { .. })
166    }
167    pub fn stable_since(&self) -> Option<StableSince> {
168        match *self {
169            StabilityLevel::Stable { since, .. } => Some(since),
170            StabilityLevel::Unstable { .. } => None,
171        }
172    }
173}
174
175#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
176#[derive(HashStable_Generic, PrintAttribute)]
177pub enum UnstableReason {
178    None,
179    Default,
180    Some(Symbol),
181}
182
183/// Represents the `#[rustc_default_body_unstable]` attribute.
184#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
185#[derive(HashStable_Generic, PrintAttribute)]
186pub struct DefaultBodyStability {
187    pub level: StabilityLevel,
188    pub feature: Symbol,
189}
190
191impl UnstableReason {
192    pub fn from_opt_reason(reason: Option<Symbol>) -> Self {
193        // UnstableReason::Default constructed manually
194        match reason {
195            Some(r) => Self::Some(r),
196            None => Self::None,
197        }
198    }
199
200    pub fn to_opt_reason(&self) -> Option<Symbol> {
201        match self {
202            Self::None => None,
203            Self::Default => Some(sym::unstable_location_reason_default),
204            Self::Some(r) => Some(*r),
205        }
206    }
207}