Skip to content

Commit a78f8e7

Browse files
committed
Refactor stability structs
This moves stability structs' `feature` fields into `StabilityLevel::Unstable` and `ConstStabilityLevel::Unstable`, in preparation to support multiple unstable attributes on items. Seemingly, the `feature` field isn't used with the `StabilityLevel::Stable` variant, so I haven't included it. `rustc_passes::lib_features` uses the 'feature' meta-item for 'stable' attributes, but it extracts them itself, rather than relying on `rustc_attr`. As a stopgap, to support the interim const stability check rules, this additionally introduces `ConstStabilityLevel` and moves the case of `feature` being `None` to the `ImplicitUnstable` variant for clarity; having it correspond to an empty `unstables` vec seems like it would be a footgun.
1 parent 42b2496 commit a78f8e7

File tree

6 files changed

+136
-100
lines changed

6 files changed

+136
-100
lines changed

compiler/rustc_attr/src/builtin.rs

Lines changed: 94 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ pub enum OptimizeAttr {
7070
#[derive(HashStable_Generic)]
7171
pub struct Stability {
7272
pub level: StabilityLevel,
73-
pub feature: Symbol,
7473
}
7574

7675
impl Stability {
@@ -88,13 +87,11 @@ impl Stability {
8887
}
8988

9089
/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
90+
/// For details see [the dev guide](https://rustc-dev-guide.rust-lang.org/stability.html#rustc_const_unstable).
9191
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
9292
#[derive(HashStable_Generic)]
9393
pub struct ConstStability {
94-
pub level: StabilityLevel,
95-
/// This can be `None` for functions that do not have an explicit const feature.
96-
/// We still track them for recursive const stability checks.
97-
pub feature: Option<Symbol>,
94+
pub level: ConstStabilityLevel,
9895
/// This is true iff the `const_stable_indirect` attribute is present.
9996
pub const_stable_indirect: bool,
10097
/// whether the function has a `#[rustc_promotable]` attribute
@@ -103,11 +100,15 @@ pub struct ConstStability {
103100

104101
impl ConstStability {
105102
pub fn is_const_unstable(&self) -> bool {
106-
self.level.is_unstable()
103+
self.level.is_const_unstable()
107104
}
108105

109106
pub fn is_const_stable(&self) -> bool {
110-
self.level.is_stable()
107+
self.level.is_const_stable()
108+
}
109+
110+
pub fn is_implicit_unstable(&self) -> bool {
111+
self.level.is_implicit_unstable()
111112
}
112113
}
113114

@@ -116,7 +117,6 @@ impl ConstStability {
116117
#[derive(HashStable_Generic)]
117118
pub struct DefaultBodyStability {
118119
pub level: StabilityLevel,
119-
pub feature: Symbol,
120120
}
121121

122122
/// The available stability levels.
@@ -125,31 +125,9 @@ pub struct DefaultBodyStability {
125125
pub enum StabilityLevel {
126126
/// `#[unstable]`
127127
Unstable {
128-
/// Reason for the current stability level.
129-
reason: UnstableReason,
130-
/// Relevant `rust-lang/rust` issue.
131-
issue: Option<NonZero<u32>>,
128+
/// The information unique to each `#[unstable]` attribute
129+
unstables: Unstability,
132130
is_soft: bool,
133-
/// If part of a feature is stabilized and a new feature is added for the remaining parts,
134-
/// then the `implied_by` attribute is used to indicate which now-stable feature previously
135-
/// contained an item.
136-
///
137-
/// ```pseudo-Rust
138-
/// #[unstable(feature = "foo", issue = "...")]
139-
/// fn foo() {}
140-
/// #[unstable(feature = "foo", issue = "...")]
141-
/// fn foobar() {}
142-
/// ```
143-
///
144-
/// ...becomes...
145-
///
146-
/// ```pseudo-Rust
147-
/// #[stable(feature = "foo", since = "1.XX.X")]
148-
/// fn foo() {}
149-
/// #[unstable(feature = "foobar", issue = "...", implied_by = "foo")]
150-
/// fn foobar() {}
151-
/// ```
152-
implied_by: Option<Symbol>,
153131
},
154132
/// `#[stable]`
155133
Stable {
@@ -161,6 +139,19 @@ pub enum StabilityLevel {
161139
},
162140
}
163141

142+
/// The available const-stability levels for const functions.
143+
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
144+
#[derive(HashStable_Generic)]
145+
pub enum ConstStabilityLevel {
146+
/// For functions declared const-stable
147+
Stable { since: StableSince },
148+
/// For functions declared const-unstable
149+
Unstable { unstables: Unstability },
150+
/// For functions with no explicit const-stability attribute that require checking recursive
151+
/// const stability. This is either an unmarked const fn or a `const_stable_indirect` intrinsic.
152+
ImplicitUnstable,
153+
}
154+
164155
/// Rust release in which a feature is stabilized.
165156
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)]
166157
#[derive(HashStable_Generic)]
@@ -187,6 +178,51 @@ impl StabilityLevel {
187178
}
188179
}
189180

181+
impl ConstStabilityLevel {
182+
pub fn is_const_unstable(&self) -> bool {
183+
matches!(self, ConstStabilityLevel::Unstable { .. } | ConstStabilityLevel::ImplicitUnstable)
184+
}
185+
186+
pub fn is_const_stable(&self) -> bool {
187+
matches!(self, ConstStabilityLevel::Stable { .. })
188+
}
189+
190+
pub fn is_implicit_unstable(&self) -> bool {
191+
matches!(self, ConstStabilityLevel::ImplicitUnstable)
192+
}
193+
}
194+
195+
/// An instance of an `#[unstable]`, `#[rustc_const_unstable]`, or similar attribute
196+
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
197+
#[derive(HashStable_Generic)]
198+
pub struct Unstability {
199+
pub feature: Symbol,
200+
/// Reason for the current stability level.
201+
pub reason: UnstableReason,
202+
/// Relevant `rust-lang/rust` issue.
203+
pub issue: Option<NonZero<u32>>,
204+
/// If part of a feature is stabilized and a new feature is added for the remaining parts,
205+
/// then the `implied_by` attribute is used to indicate which now-stable feature previously
206+
/// contained an item.
207+
///
208+
/// ```pseudo-Rust
209+
/// #[unstable(feature = "foo", issue = "...")]
210+
/// fn foo() {}
211+
/// #[unstable(feature = "foo", issue = "...")]
212+
/// fn foobar() {}
213+
/// ```
214+
///
215+
/// ...becomes...
216+
///
217+
/// ```pseudo-Rust
218+
/// #[stable(feature = "foo", since = "1.XX.X")]
219+
/// fn foo() {}
220+
/// #[unstable(feature = "foobar", issue = "...", implied_by = "foo")]
221+
/// fn foobar() {}
222+
/// ```
223+
pub implied_by: Option<Symbol>,
224+
}
225+
190226
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
191227
#[derive(HashStable_Generic)]
192228
pub enum UnstableReason {
@@ -233,8 +269,8 @@ pub fn find_stability(
233269
break;
234270
}
235271

236-
if let Some((feature, level)) = parse_unstability(sess, attr) {
237-
stab = Some((Stability { level, feature }, attr.span));
272+
if let Some(level) = parse_unstability(sess, attr) {
273+
stab = Some((Stability { level }, attr.span));
238274
}
239275
}
240276
sym::stable => {
@@ -243,8 +279,8 @@ pub fn find_stability(
243279
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
244280
break;
245281
}
246-
if let Some((feature, level)) = parse_stability(sess, attr) {
247-
stab = Some((Stability { level, feature }, attr.span));
282+
if let Some(level) = parse_stability(sess, attr) {
283+
stab = Some((Stability { level }, attr.span));
248284
}
249285
}
250286
_ => {}
@@ -283,6 +319,10 @@ pub fn find_const_stability(
283319
let mut const_stab: Option<(ConstStability, Span)> = None;
284320
let mut promotable = false;
285321
let mut const_stable_indirect = None;
322+
let const_stability_level = |level| match level {
323+
StabilityLevel::Unstable { unstables, .. } => ConstStabilityLevel::Unstable { unstables },
324+
StabilityLevel::Stable { since, .. } => ConstStabilityLevel::Stable { since },
325+
};
286326

287327
for attr in attrs {
288328
match attr.name_or_empty() {
@@ -295,11 +335,10 @@ pub fn find_const_stability(
295335
break;
296336
}
297337

298-
if let Some((feature, level)) = parse_unstability(sess, attr) {
338+
if let Some(level) = parse_unstability(sess, attr) {
299339
const_stab = Some((
300340
ConstStability {
301-
level,
302-
feature: Some(feature),
341+
level: const_stability_level(level),
303342
const_stable_indirect: false,
304343
promotable: false,
305344
},
@@ -313,11 +352,10 @@ pub fn find_const_stability(
313352
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
314353
break;
315354
}
316-
if let Some((feature, level)) = parse_stability(sess, attr) {
355+
if let Some(level) = parse_stability(sess, attr) {
317356
const_stab = Some((
318357
ConstStability {
319-
level,
320-
feature: Some(feature),
358+
level: const_stability_level(level),
321359
const_stable_indirect: false,
322360
promotable: false,
323361
},
@@ -365,15 +403,9 @@ pub fn find_const_stability(
365403
// staged_api crate.
366404
if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() {
367405
let c = ConstStability {
368-
feature: None,
406+
level: ConstStabilityLevel::ImplicitUnstable,
369407
const_stable_indirect: const_stable_indirect.is_some(),
370408
promotable: false,
371-
level: StabilityLevel::Unstable {
372-
reason: UnstableReason::Default,
373-
issue: None,
374-
is_soft: false,
375-
implied_by: None,
376-
},
377409
};
378410
const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP)));
379411
}
@@ -397,8 +429,8 @@ pub fn find_body_stability(
397429
break;
398430
}
399431

400-
if let Some((feature, level)) = parse_unstability(sess, attr) {
401-
body_stab = Some((DefaultBodyStability { level, feature }, attr.span));
432+
if let Some(level) = parse_unstability(sess, attr) {
433+
body_stab = Some((DefaultBodyStability { level }, attr.span));
402434
}
403435
}
404436
}
@@ -424,7 +456,7 @@ fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -
424456

425457
/// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and
426458
/// its stability information.
427-
fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> {
459+
fn parse_stability(sess: &Session, attr: &Attribute) -> Option<StabilityLevel> {
428460
let meta = attr.meta()?;
429461
let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None };
430462

@@ -478,17 +510,16 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
478510
};
479511

480512
match feature {
481-
Ok(feature) => {
482-
let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false };
483-
Some((feature, level))
513+
Ok(_feature) => {
514+
Some(StabilityLevel::Stable { since, allowed_through_unstable_modules: false })
484515
}
485516
Err(ErrorGuaranteed { .. }) => None,
486517
}
487518
}
488519

489520
/// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
490521
/// attribute, and return the feature name and its stability information.
491-
fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> {
522+
fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<StabilityLevel> {
492523
let meta = attr.meta()?;
493524
let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None };
494525

@@ -568,12 +599,15 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
568599
match (feature, issue) {
569600
(Ok(feature), Ok(_)) => {
570601
let level = StabilityLevel::Unstable {
571-
reason: UnstableReason::from_opt_reason(reason),
572-
issue: issue_num,
602+
unstables: Unstability {
603+
feature,
604+
reason: UnstableReason::from_opt_reason(reason),
605+
issue: issue_num,
606+
implied_by,
607+
},
573608
is_soft,
574-
implied_by,
575609
};
576-
Some((feature, level))
610+
Some(level)
577611
}
578612
(Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
579613
}

compiler/rustc_const_eval/src/check_consts/check.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::borrow::Cow;
55
use std::mem;
66
use std::ops::Deref;
77

8-
use rustc_attr::{ConstStability, StabilityLevel};
8+
use rustc_attr::{ConstStability, ConstStabilityLevel, Unstability};
99
use rustc_errors::{Diag, ErrorGuaranteed};
1010
use rustc_hir::def_id::DefId;
1111
use rustc_hir::{self as hir, LangItem};
@@ -723,7 +723,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
723723
// Non-const intrinsic.
724724
self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
725725
}
726-
Some(ConstStability { feature: None, .. }) => {
726+
Some(ConstStability {
727+
level: ConstStabilityLevel::ImplicitUnstable,
728+
..
729+
}) => {
727730
// Intrinsic does not need a separate feature gate (we rely on the
728731
// regular stability checker). However, we have to worry about recursive
729732
// const stability.
@@ -735,17 +738,18 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
735738
}
736739
}
737740
Some(ConstStability {
738-
feature: Some(feature),
739-
level: StabilityLevel::Unstable { .. },
741+
level: ConstStabilityLevel::Unstable { unstables },
740742
..
741743
}) => {
742744
self.check_op(ops::IntrinsicUnstable {
743745
name: intrinsic.name,
744-
feature,
746+
feature: unstables.feature,
745747
const_stable: is_const_stable,
746748
});
747749
}
748-
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
750+
Some(ConstStability {
751+
level: ConstStabilityLevel::Stable { .. }, ..
752+
}) => {
749753
// All good. Note that a `#[rustc_const_stable]` intrinsic (meaning it
750754
// can be *directly* invoked from stable const code) does not always
751755
// have the `#[rustc_const_stable_intrinsic]` attribute (which controls
@@ -770,10 +774,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
770774

771775
// Finally, stability for regular function calls -- this is the big one.
772776
match tcx.lookup_const_stability(callee) {
773-
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
777+
Some(ConstStability { level: ConstStabilityLevel::Stable { .. }, .. }) => {
774778
// All good.
775779
}
776-
None | Some(ConstStability { feature: None, .. }) => {
780+
None
781+
| Some(ConstStability {
782+
level: ConstStabilityLevel::ImplicitUnstable, ..
783+
}) => {
777784
// This doesn't need a separate const-stability check -- const-stability equals
778785
// regular stability, and regular stability is checked separately.
779786
// However, we *do* have to worry about *recursive* const stability.
@@ -787,10 +794,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
787794
}
788795
}
789796
Some(ConstStability {
790-
feature: Some(feature),
791-
level: StabilityLevel::Unstable { implied_by: implied_feature, .. },
797+
level: ConstStabilityLevel::Unstable { unstables },
792798
..
793799
}) => {
800+
let Unstability { feature, implied_by: implied_feature, .. } = unstables;
794801
// An unstable const fn with a feature gate.
795802
let callee_safe_to_expose_on_stable =
796803
is_safe_to_expose_on_stable_const_fn(tcx, callee);

compiler/rustc_const_eval/src/check_consts/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> b
116116
Some(stab) => {
117117
// We consider things safe-to-expose if they are stable, if they don't have any explicit
118118
// const stability attribute, or if they are marked as `const_stable_indirect`.
119-
stab.is_const_stable() || stab.feature.is_none() || stab.const_stable_indirect
119+
stab.is_const_stable() || stab.is_implicit_unstable() || stab.const_stable_indirect
120120
}
121121
}
122122
}

0 commit comments

Comments
 (0)