Skip to content

Commit 720f9e3

Browse files
committed
redo the way we do const feature inheritance
1 parent 203ca72 commit 720f9e3

File tree

13 files changed

+127
-110
lines changed

13 files changed

+127
-110
lines changed

compiler/rustc_attr/src/builtin.rs

+62-29
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
}
@@ -274,14 +276,10 @@ pub fn find_stability(
274276

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.
277-
///
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]`.
280279
pub fn find_const_stability(
281280
sess: &Session,
282281
attrs: &[Attribute],
283282
item_sp: Span,
284-
inherited_feature_gate: Option<Symbol>,
285283
) -> Option<(ConstStability, Span)> {
286284
let mut const_stab: Option<(ConstStability, Span)> = None;
287285
let mut promotable = false;
@@ -302,8 +300,9 @@ pub fn find_const_stability(
302300
const_stab = Some((
303301
ConstStability {
304302
level,
303+
has_const_stable_attr: true,
305304
feature: Some(feature),
306-
safe_to_expose_on_stable: false,
305+
const_stable_indirect: false,
307306
promotable: false,
308307
},
309308
attr.span,
@@ -320,8 +319,9 @@ pub fn find_const_stability(
320319
const_stab = Some((
321320
ConstStability {
322321
level,
322+
has_const_stable_attr: true,
323323
feature: Some(feature),
324-
safe_to_expose_on_stable: true,
324+
const_stable_indirect: false,
325325
promotable: false,
326326
},
327327
attr.span,
@@ -347,36 +347,69 @@ pub fn find_const_stability(
347347
match &mut const_stab {
348348
Some((stab, _)) => {
349349
if stab.is_const_unstable() {
350-
stab.safe_to_expose_on_stable = true;
350+
stab.const_stable_indirect = true;
351351
} else {
352352
_ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
353353
span: item_sp,
354354
})
355355
}
356356
}
357357
_ => {
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));
358+
// We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by
359+
// the `default_const_unstable` logic.
373360
}
374361
}
375362
}
376363

377364
const_stab
378365
}
379366

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

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
}

compiler/rustc_expand/src/base.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -865,11 +865,7 @@ 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 = attr::find_const_stability(sess, attrs, span);
873869
let body_stability = attr::find_body_stability(sess, attrs);
874870
if let Some((_, sp)) = const_stability {
875871
sess.dcx().emit_err(errors::MacroConstStability {

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

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)