Skip to content

Commit 80785de

Browse files
committed
redo the way we do const stability inheritance
this lets us remove a bunch of rustc_const_stable_indirect attributes
1 parent 203ca72 commit 80785de

File tree

21 files changed

+155
-129
lines changed

21 files changed

+155
-129
lines changed

Diff for: compiler/rustc_attr/src/builtin.rs

+67-33
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use rustc_session::lint::BuiltinLintDiag;
1616
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
1717
use rustc_session::parse::feature_err;
1818
use rustc_session::{RustcVersion, Session};
19+
use rustc_span::Span;
1920
use rustc_span::hygiene::Transparency;
2021
use rustc_span::symbol::{Symbol, kw, sym};
21-
use rustc_span::{DUMMY_SP, Span};
2222

2323
use crate::fluent_generated;
2424
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
@@ -92,13 +92,15 @@ impl Stability {
9292
#[derive(HashStable_Generic)]
9393
pub struct ConstStability {
9494
pub level: StabilityLevel,
95-
/// This can be `None` for functions that are not even const-unstable, but
96-
/// are tracked here for the purpose of `safe_to_expose_on_stable`.
95+
/// Says whether this function has an explicit `rustc_const_(un)stable` attribute.
96+
/// If `false`, the const stability information was inferred from the regular
97+
/// stability information.
98+
pub has_const_stable_attr: bool,
99+
/// This can be `None` for functions that are not const-callable from outside code under any
100+
/// feature gate, but are tracked here for the purpose of `safe_to_expose_on_stable`.
97101
pub feature: Option<Symbol>,
98-
/// A function that is marked as "safe to expose on stable" must not use any unstable const
99-
/// language features or intrinsics, and all the functions it calls must also be safe to expose
100-
/// on stable. If `level` is `Stable`, this must be `true`.
101-
pub safe_to_expose_on_stable: bool,
102+
/// This is true iff the `const_stable_indirect` attribute is present.
103+
pub const_stable_indirect: bool,
102104
/// whether the function has a `#[rustc_promotable]` attribute
103105
pub promotable: bool,
104106
}
@@ -275,22 +277,21 @@ pub fn find_stability(
275277
/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
276278
/// attributes in `attrs`. Returns `None` if no stability attributes are found.
277279
///
278-
/// `inherited_feature_gate` says which feature gate this function should be under if it doesn't
279-
/// declare a gate itself, but has `#[rustc_const_stable_indirect]`.
280+
/// The second component is the `const_stable_indirect` attribute if present, which can be meaningful
281+
/// even if there is no `rustc_const_stable`/`rustc_const_unstable`.
280282
pub fn find_const_stability(
281283
sess: &Session,
282284
attrs: &[Attribute],
283285
item_sp: Span,
284-
inherited_feature_gate: Option<Symbol>,
285-
) -> Option<(ConstStability, Span)> {
286+
) -> (Option<(ConstStability, Span)>, Option<Span>) {
286287
let mut const_stab: Option<(ConstStability, Span)> = None;
287288
let mut promotable = false;
288-
let mut const_stable_indirect = false;
289+
let mut const_stable_indirect = None;
289290

290291
for attr in attrs {
291292
match attr.name_or_empty() {
292293
sym::rustc_promotable => promotable = true,
293-
sym::rustc_const_stable_indirect => const_stable_indirect = true,
294+
sym::rustc_const_stable_indirect => const_stable_indirect = Some(attr.span),
294295
sym::rustc_const_unstable => {
295296
if const_stab.is_some() {
296297
sess.dcx()
@@ -302,8 +303,9 @@ pub fn find_const_stability(
302303
const_stab = Some((
303304
ConstStability {
304305
level,
306+
has_const_stable_attr: true,
305307
feature: Some(feature),
306-
safe_to_expose_on_stable: false,
308+
const_stable_indirect: false,
307309
promotable: false,
308310
},
309311
attr.span,
@@ -320,8 +322,9 @@ pub fn find_const_stability(
320322
const_stab = Some((
321323
ConstStability {
322324
level,
325+
has_const_stable_attr: true,
323326
feature: Some(feature),
324-
safe_to_expose_on_stable: true,
327+
const_stable_indirect: false,
325328
promotable: false,
326329
},
327330
attr.span,
@@ -343,38 +346,69 @@ pub fn find_const_stability(
343346
}
344347
}
345348
}
346-
if const_stable_indirect {
349+
if const_stable_indirect.is_some() {
347350
match &mut const_stab {
348351
Some((stab, _)) => {
349352
if stab.is_const_unstable() {
350-
stab.safe_to_expose_on_stable = true;
353+
stab.const_stable_indirect = true;
351354
} else {
352355
_ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
353356
span: item_sp,
354357
})
355358
}
356359
}
357360
_ => {
358-
// `#[rustc_const_stable_indirect]` implicitly makes the function unstably const,
359-
// inheriting the feature gate from `#[unstable]` if it xists, or without any
360-
// feature gate otherwise.
361-
let c = ConstStability {
362-
feature: inherited_feature_gate,
363-
safe_to_expose_on_stable: true,
364-
promotable: false,
365-
level: StabilityLevel::Unstable {
366-
reason: UnstableReason::Default,
367-
issue: None,
368-
is_soft: false,
369-
implied_by: None,
370-
},
371-
};
372-
const_stab = Some((c, DUMMY_SP));
361+
// We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by
362+
// the `default_const_unstable` logic.
373363
}
374364
}
375365
}
376366

377-
const_stab
367+
(const_stab, const_stable_indirect)
368+
}
369+
370+
/// Called for `fn` that don't have a const stability.
371+
///
372+
/// `effective_reg_stability` must be the effecive regular stability, i.e. after applying all the
373+
/// rules about "inherited" stability.
374+
pub fn default_const_stability(
375+
_sess: &Session,
376+
is_const_fn: bool,
377+
const_stable_indirect: bool,
378+
effective_reg_stability: Option<&Stability>,
379+
) -> Option<ConstStability> {
380+
// Intrinsics are *not* `const fn` here, and yet we want to add a default const stability
381+
// for them if they are marked `const_stable_indirect`.
382+
if (is_const_fn || const_stable_indirect)
383+
&& let Some(reg_stability) = effective_reg_stability
384+
&& reg_stability.level.is_unstable()
385+
{
386+
// This has a feature gate, reuse that for const stability.
387+
// We only want to do this if it is an unstable feature gate.
388+
Some(ConstStability {
389+
feature: Some(reg_stability.feature),
390+
has_const_stable_attr: false,
391+
const_stable_indirect,
392+
promotable: false,
393+
level: reg_stability.level,
394+
})
395+
} else if const_stable_indirect {
396+
// Make it const-unstable without a feature gate, to record the `const_stable_indirect`.
397+
Some(ConstStability {
398+
feature: None,
399+
has_const_stable_attr: false,
400+
const_stable_indirect,
401+
promotable: false,
402+
level: StabilityLevel::Unstable {
403+
reason: UnstableReason::Default,
404+
issue: None,
405+
is_soft: false,
406+
implied_by: None,
407+
},
408+
})
409+
} else {
410+
None
411+
}
378412
}
379413

380414
/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`.

Diff for: compiler/rustc_const_eval/src/check_consts/mod.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,16 @@ pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> b
120120
// We allow calling unmarked local functions *in the current crate*. For the cross-crate
121121
// case we require the other crate to explicitly add `#[rustc_const_stable_indirect]` as
122122
// a promise that this function is meant to be indirectly const-stable, which will make
123-
// `lookup_const_stability` return `Some`.
123+
// `lookup_const_stability` return `Some`. This ensures that the other crate checked
124+
// recursive const vailidty on that function, even if the other crate is not using
125+
// `staged_api`.
124126
def_id.is_local()
125127
}
126128
Some(stab) => {
127-
// `safe_to_expose_on_stable` implies `is_const_stable`.
128-
if stab.is_const_stable() {
129-
assert!(stab.safe_to_expose_on_stable);
130-
}
131-
stab.safe_to_expose_on_stable
129+
stab.is_const_stable() || stab.const_stable_indirect ||
130+
// Non-intrinsic `const fn` without an explicit const stability attribute (i.e.,
131+
// with only the implied attribute) are safe to expose on stable.
132+
(!stab.has_const_stable_attr && tcx.intrinsic(def_id).is_none())
132133
}
133134
}
134135
}

Diff for: compiler/rustc_expand/src/base.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -865,18 +865,21 @@ impl SyntaxExtension {
865865
})
866866
.unwrap_or_else(|| (None, helper_attrs));
867867
let stability = attr::find_stability(sess, attrs, span);
868-
// FIXME: this will give a different result than the normal stability computation, since we
869-
// don't inherit stability from the parent. But that's true even for `stability` above so
870-
// it's probably okay?
871-
let const_stability =
872-
attr::find_const_stability(sess, attrs, span, stability.map(|(s, _)| s.feature));
868+
let (const_stability, const_stable_indirect) =
869+
attr::find_const_stability(sess, attrs, span);
873870
let body_stability = attr::find_body_stability(sess, attrs);
874871
if let Some((_, sp)) = const_stability {
875872
sess.dcx().emit_err(errors::MacroConstStability {
876873
span: sp,
877874
head_span: sess.source_map().guess_head_span(span),
878875
});
879876
}
877+
if let Some(sp) = const_stable_indirect {
878+
sess.dcx().emit_err(errors::MacroConstStability {
879+
span: sp,
880+
head_span: sess.source_map().guess_head_span(span),
881+
});
882+
}
880883
if let Some((_, sp)) = body_stability {
881884
sess.dcx().emit_err(errors::MacroBodyStability {
882885
span: sp,

Diff for: compiler/rustc_passes/messages.ftl

-1
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,6 @@ passes_maybe_string_interpolation = you might have meant to use string interpola
456456
passes_missing_const_err =
457457
attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
458458
.help = make the function or method const
459-
.label = attribute specified here
460459
461460
passes_missing_const_stab_attr =
462461
{$descr} has missing const stability attribute

Diff for: compiler/rustc_passes/src/errors.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1551,8 +1551,6 @@ pub(crate) struct MissingConstErr {
15511551
#[primary_span]
15521552
#[help]
15531553
pub fn_sig_span: Span,
1554-
#[label]
1555-
pub const_span: Span,
15561554
}
15571555

15581556
#[derive(Diagnostic)]

0 commit comments

Comments
 (0)