rustc_attr_data_structures/
stability.rs

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