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        old_name: Option<Symbol>,
136    },
137    /// `#[stable]`
138    Stable {
139        /// Rust release which stabilized this feature.
140        since: StableSince,
141        /// This is `Some` if this item allowed to be referred to on stable via unstable modules;
142        /// the `Symbol` is the deprecation message printed in that case.
143        allowed_through_unstable_modules: Option<Symbol>,
144    },
145}
146
147/// Rust release in which a feature is stabilized.
148#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)]
149#[derive(HashStable_Generic, PrintAttribute)]
150pub enum StableSince {
151    /// also stores the original symbol for printing
152    Version(RustcVersion),
153    /// Stabilized in the upcoming version, whatever number that is.
154    Current,
155    /// Failed to parse a stabilization version.
156    Err,
157}
158
159impl StabilityLevel {
160    pub fn is_unstable(&self) -> bool {
161        matches!(self, StabilityLevel::Unstable { .. })
162    }
163    pub fn is_stable(&self) -> bool {
164        matches!(self, StabilityLevel::Stable { .. })
165    }
166    pub fn stable_since(&self) -> Option<StableSince> {
167        match *self {
168            StabilityLevel::Stable { since, .. } => Some(since),
169            StabilityLevel::Unstable { .. } => None,
170        }
171    }
172}
173
174#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
175#[derive(HashStable_Generic, PrintAttribute)]
176pub enum UnstableReason {
177    None,
178    Default,
179    Some(Symbol),
180}
181
182/// Represents the `#[rustc_default_body_unstable]` attribute.
183#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
184#[derive(HashStable_Generic, PrintAttribute)]
185pub struct DefaultBodyStability {
186    pub level: StabilityLevel,
187    pub feature: Symbol,
188}
189
190impl UnstableReason {
191    pub fn from_opt_reason(reason: Option<Symbol>) -> Self {
192        // UnstableReason::Default constructed manually
193        match reason {
194            Some(r) => Self::Some(r),
195            None => Self::None,
196        }
197    }
198
199    pub fn to_opt_reason(&self) -> Option<Symbol> {
200        match self {
201            Self::None => None,
202            Self::Default => Some(sym::unstable_location_reason_default),
203            Self::Some(r) => Some(*r),
204        }
205    }
206}