Skip to content

Commit 666d312

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 3f1be1e commit 666d312

File tree

6 files changed

+120
-100
lines changed

6 files changed

+120
-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
_ => {}
@@ -284,6 +306,10 @@ pub fn find_const_stability(
284306
let mut const_stab: Option<(ConstStability, Span)> = None;
285307
let mut promotable = false;
286308
let mut const_stable_indirect = None;
309+
let const_stability_level = |level| match level {
310+
StabilityLevel::Unstable { unstables, .. } => ConstStabilityLevel::Unstable { unstables },
311+
StabilityLevel::Stable { since, .. } => ConstStabilityLevel::Stable { since },
312+
};
287313

288314
for attr in attrs {
289315
match attr.name_or_empty() {
@@ -296,11 +322,10 @@ pub fn find_const_stability(
296322
break;
297323
}
298324

299-
if let Some((feature, level)) = parse_unstability(sess, attr) {
325+
if let Some(level) = parse_unstability(sess, attr) {
300326
const_stab = Some((
301327
ConstStability {
302-
level,
303-
feature: Some(feature),
328+
level: const_stability_level(level),
304329
const_stable_indirect: false,
305330
promotable: false,
306331
},
@@ -314,11 +339,10 @@ pub fn find_const_stability(
314339
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
315340
break;
316341
}
317-
if let Some((feature, level)) = parse_stability(sess, attr) {
342+
if let Some(level) = parse_stability(sess, attr) {
318343
const_stab = Some((
319344
ConstStability {
320-
level,
321-
feature: Some(feature),
345+
level: const_stability_level(level),
322346
const_stable_indirect: false,
323347
promotable: false,
324348
},
@@ -369,15 +393,9 @@ pub fn find_const_stability(
369393
// staged_api crate.
370394
if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() {
371395
let c = ConstStability {
372-
feature: None,
396+
level: ConstStabilityLevel::Implicit,
373397
const_stable_indirect: const_stable_indirect.is_some(),
374398
promotable: false,
375-
level: StabilityLevel::Unstable {
376-
reason: UnstableReason::Default,
377-
issue: None,
378-
is_soft: false,
379-
implied_by: None,
380-
},
381399
};
382400
const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP)));
383401
}
@@ -401,8 +419,8 @@ pub fn find_body_stability(
401419
break;
402420
}
403421

404-
if let Some((feature, level)) = parse_unstability(sess, attr) {
405-
body_stab = Some((DefaultBodyStability { level, feature }, attr.span));
422+
if let Some(level) = parse_unstability(sess, attr) {
423+
body_stab = Some((DefaultBodyStability { level }, attr.span));
406424
}
407425
}
408426
}
@@ -428,7 +446,7 @@ fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -
428446

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

@@ -482,17 +500,16 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
482500
};
483501

484502
match feature {
485-
Ok(feature) => {
486-
let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false };
487-
Some((feature, level))
503+
Ok(_feature) => {
504+
Some(StabilityLevel::Stable { since, allowed_through_unstable_modules: false })
488505
}
489506
Err(ErrorGuaranteed { .. }) => None,
490507
}
491508
}
492509

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

@@ -572,12 +589,15 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
572589
match (feature, issue) {
573590
(Ok(feature), Ok(_)) => {
574591
let level = StabilityLevel::Unstable {
575-
reason: UnstableReason::from_opt_reason(reason),
576-
issue: issue_num,
592+
unstables: Unstability {
593+
feature,
594+
reason: UnstableReason::from_opt_reason(reason),
595+
issue: issue_num,
596+
implied_by,
597+
},
577598
is_soft,
578-
implied_by,
579599
};
580-
Some((feature, level))
600+
Some(level)
581601
}
582602
(Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
583603
}

compiler/rustc_const_eval/src/check_consts/check.rs

Lines changed: 15 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};
@@ -708,7 +708,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
708708
// Non-const intrinsic.
709709
self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
710710
}
711-
Some(ConstStability { feature: None, const_stable_indirect, .. }) => {
711+
Some(ConstStability {
712+
level: ConstStabilityLevel::Implicit,
713+
const_stable_indirect,
714+
..
715+
}) => {
712716
// Intrinsic does not need a separate feature gate (we rely on the
713717
// regular stability checker). However, we have to worry about recursive
714718
// const stability.
@@ -720,18 +724,19 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
720724
}
721725
}
722726
Some(ConstStability {
723-
feature: Some(feature),
724-
level: StabilityLevel::Unstable { .. },
727+
level: ConstStabilityLevel::Unstable { unstables },
725728
const_stable_indirect,
726729
..
727730
}) => {
728731
self.check_op(ops::IntrinsicUnstable {
729732
name: intrinsic.name,
730-
feature,
733+
feature: unstables.feature,
731734
const_stable_indirect,
732735
});
733736
}
734-
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
737+
Some(ConstStability {
738+
level: ConstStabilityLevel::Stable { .. }, ..
739+
}) => {
735740
// All good.
736741
}
737742
}
@@ -756,10 +761,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
756761

757762
// Finally, stability for regular function calls -- this is the big one.
758763
match tcx.lookup_const_stability(callee) {
759-
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
764+
Some(ConstStability { level: ConstStabilityLevel::Stable { .. }, .. }) => {
760765
// All good.
761766
}
762-
None | Some(ConstStability { feature: None, .. }) => {
767+
None | Some(ConstStability { level: ConstStabilityLevel::Implicit, .. }) => {
763768
// This doesn't need a separate const-stability check -- const-stability equals
764769
// regular stability, and regular stability is checked separately.
765770
// However, we *do* have to worry about *recursive* const stability.
@@ -773,10 +778,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
773778
}
774779
}
775780
Some(ConstStability {
776-
feature: Some(feature),
777-
level: StabilityLevel::Unstable { implied_by: implied_feature, .. },
781+
level: ConstStabilityLevel::Unstable { unstables },
778782
..
779783
}) => {
784+
let Unstability { feature, implied_by: implied_feature, .. } = unstables;
780785
// An unstable const fn with a feature gate.
781786
let callee_safe_to_expose_on_stable =
782787
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
@@ -123,7 +123,7 @@ pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> b
123123
Some(stab) => {
124124
// We consider things safe-to-expose if they are stable, if they don't have any explicit
125125
// const stability attribute, or if they are marked as `const_stable_indirect`.
126-
stab.is_const_stable() || stab.feature.is_none() || stab.const_stable_indirect
126+
stab.is_const_stable() || stab.is_implicit() || stab.const_stable_indirect
127127
}
128128
}
129129
}

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)