1use std::num::NonZero;23use rustc_ast::attr::version::RustcVersion;4use rustc_macros::{BlobDecodable, Decodable, Encodable, PrintAttribute, StableHash};5use rustc_span::{ErrorGuaranteed, Symbol, sym};67use crate::PrintAttribute;89/// The version placeholder that recently stabilized features contain inside the10/// `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` from15// replacing the constant with the current version. Hardcoding the tool to skip this file doesn't16// 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 :(1920/// Represents the following attributes:21///22/// - `#[stable]`23/// - `#[unstable]`24#[derive(Encodable, BlobDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]25#[derive(StableHash, PrintAttribute)]26pub struct Stability {27 pub level: StabilityLevel,28 pub feature: Symbol,29}3031impl Stability {32 pub fn is_unstable(&self) -> bool {33 self.level.is_unstable()34 }3536 pub fn is_stable(&self) -> bool {37 self.level.is_stable()38 }3940 pub fn stable_since(&self) -> Option<StableSince> {41 self.level.stable_since()42 }43}4445/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.46#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]47#[derive(StableHash, PrintAttribute)]48pub struct ConstStability {49 pub level: StabilityLevel,50 pub feature: Symbol,51 /// whether the function has a `#[rustc_promotable]` attribute52 pub promotable: bool,53 /// This is true iff the `const_stable_indirect` attribute is present.54 pub const_stable_indirect: bool,55}5657impl 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 }6465 /// 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 }7475 pub fn is_const_unstable(&self) -> bool {76 self.level.is_unstable()77 }7879 pub fn is_const_stable(&self) -> bool {80 self.level.is_stable()81 }82}8384/// 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]` attributes86#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]87#[derive(StableHash, PrintAttribute)]88pub struct PartialConstStability {89 pub level: StabilityLevel,90 pub feature: Symbol,91 /// whether the function has a `#[rustc_promotable]` attribute92 pub promotable: bool,93}9495impl PartialConstStability {96 pub fn is_const_unstable(&self) -> bool {97 self.level.is_unstable()98 }99100 pub fn is_const_stable(&self) -> bool {101 self.level.is_stable()102 }103}104105/// The available stability levels.106#[derive(Encodable, BlobDecodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]107#[derive(StableHash, 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 /// 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 previously117 /// contained an item.118 ///119 /// ```pseudo-Rust120 /// #[unstable(feature = "foo", issue = "...")]121 /// fn foo() {}122 /// #[unstable(feature = "foo", issue = "...")]123 /// fn foobar() {}124 /// ```125 ///126 /// ...becomes...127 ///128 /// ```pseudo-Rust129 /// #[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}146147/// Rust release in which a feature is stabilized.148#[derive(Encodable, BlobDecodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)]149#[derive(StableHash, PrintAttribute)]150pub enum StableSince {151 /// also stores the original symbol for printing152 Version(RustcVersion),153 /// Stabilized in the upcoming version, whatever number that is.154 Current,155 /// Failed to parse a stabilization version.156 Err(ErrorGuaranteed),157}158159impl 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}173174#[derive(Encodable, BlobDecodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]175#[derive(StableHash, PrintAttribute)]176pub enum UnstableReason {177 None,178 Default,179 Some(Symbol),180}181182/// Represents the `#[rustc_default_body_unstable]` attribute.183#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]184#[derive(StableHash, PrintAttribute)]185pub struct DefaultBodyStability {186 pub level: StabilityLevel,187 pub feature: Symbol,188}189190impl UnstableReason {191 pub fn from_opt_reason(reason: Option<Symbol>) -> Self {192 // UnstableReason::Default constructed manually193 match reason {194 Some(r) => Self::Some(r),195 None => Self::None,196 }197 }198199 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}