Skip to content

Commit 9e13239

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`. In order to support the new const stability check rules, this additionally introduces `ConstStabilityLevel` and moves the case of `feature` being `None` to the `Implicit` variant for clarity; having it correspond to an empty `unstables` vec seems like it would be a footgun.
1 parent bc5cf99 commit 9e13239

File tree

6 files changed

+116
-100
lines changed

6 files changed

+116
-100
lines changed

compiler/rustc_attr/src/builtin.rs

Lines changed: 80 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 {
@@ -91,10 +90,7 @@ impl Stability {
9190
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
9291
#[derive(HashStable_Generic)]
9392
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>,
93+
pub level: ConstStabilityLevel,
9894
/// This is true iff the `const_stable_indirect` attribute is present.
9995
pub const_stable_indirect: bool,
10096
/// whether the function has a `#[rustc_promotable]` attribute
@@ -103,11 +99,15 @@ pub struct ConstStability {
10399

104100
impl ConstStability {
105101
pub fn is_const_unstable(&self) -> bool {
106-
self.level.is_unstable()
102+
matches!(self.level, ConstStabilityLevel::Unstable { .. })
107103
}
108104

109105
pub fn is_const_stable(&self) -> bool {
110-
self.level.is_stable()
106+
matches!(self.level, ConstStabilityLevel::Stable { .. })
107+
}
108+
109+
pub fn is_implicit(&self) -> bool {
110+
matches!(self.level, ConstStabilityLevel::Implicit)
111111
}
112112
}
113113

@@ -116,7 +116,6 @@ impl ConstStability {
116116
#[derive(HashStable_Generic)]
117117
pub struct DefaultBodyStability {
118118
pub level: StabilityLevel,
119-
pub feature: Symbol,
120119
}
121120

122121
/// The available stability levels.
@@ -125,31 +124,9 @@ pub struct DefaultBodyStability {
125124
pub enum StabilityLevel {
126125
/// `#[unstable]`
127126
Unstable {
128-
/// Reason for the current stability level.
129-
reason: UnstableReason,
130-
/// Relevant `rust-lang/rust` issue.
131-
issue: Option<NonZero<u32>>,
127+
/// The information unique to each `#[unstable]` attribute
128+
unstables: Unstability,
132129
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>,
153130
},
154131
/// `#[stable]`
155132
Stable {
@@ -161,6 +138,20 @@ pub enum StabilityLevel {
161138
},
162139
}
163140

141+
/// The available const-stability levels for const functions.
142+
/// For details see [#131349](https://github.com/rust-lang/rust/pull/131349).
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+
Implicit,
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,37 @@ impl StabilityLevel {
187178
}
188179
}
189180

181+
/// An instance of an `#[unstable]`, `#[rustc_const_unstable]`, or similar attribute
182+
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
183+
#[derive(HashStable_Generic)]
184+
pub struct Unstability {
185+
pub feature: Symbol,
186+
/// Reason for the current stability level.
187+
pub reason: UnstableReason,
188+
/// Relevant `rust-lang/rust` issue.
189+
pub issue: Option<NonZero<u32>>,
190+
/// If part of a feature is stabilized and a new feature is added for the remaining parts,
191+
/// then the `implied_by` attribute is used to indicate which now-stable feature previously
192+
/// contained an item.
193+
///
194+
/// ```pseudo-Rust
195+
/// #[unstable(feature = "foo", issue = "...")]
196+
/// fn foo() {}
197+
/// #[unstable(feature = "foo", issue = "...")]
198+
/// fn foobar() {}
199+
/// ```
200+
///
201+
/// ...becomes...
202+
///
203+
/// ```pseudo-Rust
204+
/// #[stable(feature = "foo", since = "1.XX.X")]
205+
/// fn foo() {}
206+
/// #[unstable(feature = "foobar", issue = "...", implied_by = "foo")]
207+
/// fn foobar() {}
208+
/// ```
209+
pub implied_by: Option<Symbol>,
210+
}
211+
190212
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
191213
#[derive(HashStable_Generic)]
192214
pub enum UnstableReason {
@@ -233,8 +255,8 @@ pub fn find_stability(
233255
break;
234256
}
235257

236-
if let Some((feature, level)) = parse_unstability(sess, attr) {
237-
stab = Some((Stability { level, feature }, attr.span));
258+
if let Some(level) = parse_unstability(sess, attr) {
259+
stab = Some((Stability { level }, attr.span));
238260
}
239261
}
240262
sym::stable => {
@@ -243,8 +265,8 @@ pub fn find_stability(
243265
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
244266
break;
245267
}
246-
if let Some((feature, level)) = parse_stability(sess, attr) {
247-
stab = Some((Stability { level, feature }, attr.span));
268+
if let Some(level) = parse_stability(sess, attr) {
269+
stab = Some((Stability { level }, attr.span));
248270
}
249271
}
250272
_ => {}
@@ -283,6 +305,10 @@ pub fn find_const_stability(
283305
let mut const_stab: Option<(ConstStability, Span)> = None;
284306
let mut promotable = false;
285307
let mut const_stable_indirect = None;
308+
let const_stability_level = |level| match level {
309+
StabilityLevel::Unstable { unstables, .. } => ConstStabilityLevel::Unstable { unstables },
310+
StabilityLevel::Stable { since, .. } => ConstStabilityLevel::Stable { since },
311+
};
286312

287313
for attr in attrs {
288314
match attr.name_or_empty() {
@@ -295,11 +321,10 @@ pub fn find_const_stability(
295321
break;
296322
}
297323

298-
if let Some((feature, level)) = parse_unstability(sess, attr) {
324+
if let Some(level) = parse_unstability(sess, attr) {
299325
const_stab = Some((
300326
ConstStability {
301-
level,
302-
feature: Some(feature),
327+
level: const_stability_level(level),
303328
const_stable_indirect: false,
304329
promotable: false,
305330
},
@@ -313,11 +338,10 @@ pub fn find_const_stability(
313338
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
314339
break;
315340
}
316-
if let Some((feature, level)) = parse_stability(sess, attr) {
341+
if let Some(level) = parse_stability(sess, attr) {
317342
const_stab = Some((
318343
ConstStability {
319-
level,
320-
feature: Some(feature),
344+
level: const_stability_level(level),
321345
const_stable_indirect: false,
322346
promotable: false,
323347
},
@@ -365,15 +389,9 @@ pub fn find_const_stability(
365389
// staged_api crate.
366390
if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() {
367391
let c = ConstStability {
368-
feature: None,
392+
level: ConstStabilityLevel::Implicit,
369393
const_stable_indirect: const_stable_indirect.is_some(),
370394
promotable: false,
371-
level: StabilityLevel::Unstable {
372-
reason: UnstableReason::Default,
373-
issue: None,
374-
is_soft: false,
375-
implied_by: None,
376-
},
377395
};
378396
const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP)));
379397
}
@@ -397,8 +415,8 @@ pub fn find_body_stability(
397415
break;
398416
}
399417

400-
if let Some((feature, level)) = parse_unstability(sess, attr) {
401-
body_stab = Some((DefaultBodyStability { level, feature }, attr.span));
418+
if let Some(level) = parse_unstability(sess, attr) {
419+
body_stab = Some((DefaultBodyStability { level }, attr.span));
402420
}
403421
}
404422
}
@@ -424,7 +442,7 @@ fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -
424442

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

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

480498
match feature {
481-
Ok(feature) => {
482-
let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false };
483-
Some((feature, level))
499+
Ok(_feature) => {
500+
Some(StabilityLevel::Stable { since, allowed_through_unstable_modules: false })
484501
}
485502
Err(ErrorGuaranteed { .. }) => None,
486503
}
487504
}
488505

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

@@ -568,12 +585,15 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
568585
match (feature, issue) {
569586
(Ok(feature), Ok(_)) => {
570587
let level = StabilityLevel::Unstable {
571-
reason: UnstableReason::from_opt_reason(reason),
572-
issue: issue_num,
588+
unstables: Unstability {
589+
feature,
590+
reason: UnstableReason::from_opt_reason(reason),
591+
issue: issue_num,
592+
implied_by,
593+
},
573594
is_soft,
574-
implied_by,
575595
};
576-
Some((feature, level))
596+
Some(level)
577597
}
578598
(Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
579599
}

compiler/rustc_const_eval/src/check_consts/check.rs

Lines changed: 11 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};
@@ -750,7 +750,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
750750
// Non-const intrinsic.
751751
self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
752752
}
753-
Some(ConstStability { feature: None, .. }) => {
753+
Some(ConstStability { level: ConstStabilityLevel::Implicit, .. }) => {
754754
// Intrinsic does not need a separate feature gate (we rely on the
755755
// regular stability checker). However, we have to worry about recursive
756756
// const stability.
@@ -762,17 +762,18 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
762762
}
763763
}
764764
Some(ConstStability {
765-
feature: Some(feature),
766-
level: StabilityLevel::Unstable { .. },
765+
level: ConstStabilityLevel::Unstable { unstables },
767766
..
768767
}) => {
769768
self.check_op(ops::IntrinsicUnstable {
770769
name: intrinsic.name,
771-
feature,
770+
feature: unstables.feature,
772771
const_stable: is_const_stable,
773772
});
774773
}
775-
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
774+
Some(ConstStability {
775+
level: ConstStabilityLevel::Stable { .. }, ..
776+
}) => {
776777
// All good. Note that a `#[rustc_const_stable]` intrinsic (meaning it
777778
// can be *directly* invoked from stable const code) does not always
778779
// have the `#[rustc_const_stable_intrinsic]` attribute (which controls
@@ -799,10 +800,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
799800

800801
// Finally, stability for regular function calls -- this is the big one.
801802
match tcx.lookup_const_stability(callee) {
802-
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
803+
Some(ConstStability { level: ConstStabilityLevel::Stable { .. }, .. }) => {
803804
// All good.
804805
}
805-
None | Some(ConstStability { feature: None, .. }) => {
806+
None | Some(ConstStability { level: ConstStabilityLevel::Implicit, .. }) => {
806807
// This doesn't need a separate const-stability check -- const-stability equals
807808
// regular stability, and regular stability is checked separately.
808809
// However, we *do* have to worry about *recursive* const stability.
@@ -816,10 +817,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
816817
}
817818
}
818819
Some(ConstStability {
819-
feature: Some(feature),
820-
level: StabilityLevel::Unstable { implied_by: implied_feature, .. },
820+
level: ConstStabilityLevel::Unstable { unstables },
821821
..
822822
}) => {
823+
let Unstability { feature, implied_by: implied_feature, .. } = unstables;
823824
// An unstable const fn with a feature gate.
824825
let callee_safe_to_expose_on_stable =
825826
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() || stab.const_stable_indirect
120120
}
121121
}
122122
}

compiler/rustc_middle/src/middle/stability.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -413,11 +413,8 @@ impl<'tcx> TyCtxt<'tcx> {
413413
}
414414

415415
match stability {
416-
Some(Stability {
417-
level: attr::Unstable { reason, issue, is_soft, implied_by },
418-
feature,
419-
..
420-
}) => {
416+
Some(Stability { level: attr::Unstable { unstables, is_soft } }) => {
417+
let attr::Unstability { feature, reason, issue, implied_by } = unstables;
421418
if span.allows_unstable(feature) {
422419
debug!("stability: skipping span={:?} since it is internal", span);
423420
return EvalResult::Allow;
@@ -501,10 +498,8 @@ impl<'tcx> TyCtxt<'tcx> {
501498
}
502499

503500
match stability {
504-
Some(DefaultBodyStability {
505-
level: attr::Unstable { reason, issue, is_soft, .. },
506-
feature,
507-
}) => {
501+
Some(DefaultBodyStability { level: attr::Unstable { unstables, is_soft } }) => {
502+
let attr::Unstability { feature, reason, issue, .. } = unstables;
508503
if span.allows_unstable(feature) {
509504
debug!("body stability: skipping span={:?} since it is internal", span);
510505
return EvalResult::Allow;

0 commit comments

Comments
 (0)