Skip to content

Commit 658a329

Browse files
committed
ensure that all publicly reachable const fn have const stability info
1 parent 0cf1a81 commit 658a329

File tree

15 files changed

+188
-242
lines changed

15 files changed

+188
-242
lines changed

compiler/rustc_attr/src/builtin.rs

+13-37
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,9 +92,7 @@ impl Stability {
9292
#[derive(HashStable_Generic)]
9393
pub struct ConstStability {
9494
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>,
95+
pub feature: Symbol,
9896
/// This is true iff the `const_stable_indirect` attribute is present.
9997
pub const_stable_indirect: bool,
10098
/// whether the function has a `#[rustc_promotable]` attribute
@@ -272,22 +270,19 @@ pub fn find_stability(
272270

273271
/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
274272
/// attributes in `attrs`. Returns `None` if no stability attributes are found.
275-
///
276-
/// `is_const_fn` indicates whether this is a function marked as `const`.
277273
pub fn find_const_stability(
278274
sess: &Session,
279275
attrs: &[Attribute],
280276
item_sp: Span,
281-
is_const_fn: bool,
282277
) -> Option<(ConstStability, Span)> {
283278
let mut const_stab: Option<(ConstStability, Span)> = None;
284279
let mut promotable = false;
285-
let mut const_stable_indirect = None;
280+
let mut const_stable_indirect = false;
286281

287282
for attr in attrs {
288283
match attr.name_or_empty() {
289284
sym::rustc_promotable => promotable = true,
290-
sym::rustc_const_stable_indirect => const_stable_indirect = Some(attr.span),
285+
sym::rustc_const_stable_indirect => const_stable_indirect = true,
291286
sym::rustc_const_unstable => {
292287
if const_stab.is_some() {
293288
sess.dcx()
@@ -299,7 +294,7 @@ pub fn find_const_stability(
299294
const_stab = Some((
300295
ConstStability {
301296
level,
302-
feature: Some(feature),
297+
feature,
303298
const_stable_indirect: false,
304299
promotable: false,
305300
},
@@ -317,7 +312,7 @@ pub fn find_const_stability(
317312
const_stab = Some((
318313
ConstStability {
319314
level,
320-
feature: Some(feature),
315+
feature,
321316
const_stable_indirect: false,
322317
promotable: false,
323318
},
@@ -340,7 +335,7 @@ pub fn find_const_stability(
340335
}
341336
}
342337
}
343-
if const_stable_indirect.is_some() {
338+
if const_stable_indirect {
344339
match &mut const_stab {
345340
Some((stab, _)) => {
346341
if stab.is_const_unstable() {
@@ -351,32 +346,13 @@ pub fn find_const_stability(
351346
})
352347
}
353348
}
354-
_ => {}
349+
_ => {
350+
// This function has no const stability attribute, but has `const_stable_indirect`.
351+
// We ignore that; unmarked functions are subject to recursive const stability
352+
// checks by default so we do carry out the user's intent.
353+
}
355354
}
356355
}
357-
// Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const
358-
// fn` get *some* marker, since we are a staged_api crate and therefore will do recursive const
359-
// stability checks for them. We need to do this because the default for whether an unmarked
360-
// function enforces recursive stability differs between staged-api crates and force-unmarked
361-
// crates: in force-unmarked crates, only functions *explicitly* marked `const_stable_indirect`
362-
// enforce recursive stability. Therefore when `lookup_const_stability` is `None`, we have to
363-
// assume the function does not have recursive stability. All functions that *do* have recursive
364-
// stability must explicitly record this, and so that's what we do for all `const fn` in a
365-
// staged_api crate.
366-
if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() {
367-
let c = ConstStability {
368-
feature: None,
369-
const_stable_indirect: const_stable_indirect.is_some(),
370-
promotable: false,
371-
level: StabilityLevel::Unstable {
372-
reason: UnstableReason::Default,
373-
issue: None,
374-
is_soft: false,
375-
implied_by: None,
376-
},
377-
};
378-
const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP)));
379-
}
380356

381357
const_stab
382358
}
@@ -394,7 +370,7 @@ pub fn unmarked_crate_const_stab(
394370
let const_stable_indirect =
395371
attrs.iter().any(|a| a.name_or_empty() == sym::rustc_const_stable_indirect);
396372
ConstStability {
397-
feature: Some(regular_stab.feature),
373+
feature: regular_stab.feature,
398374
const_stable_indirect,
399375
promotable: false,
400376
level: regular_stab.level,

compiler/rustc_const_eval/src/check_consts/check.rs

+13-11
Original file line numberDiff line numberDiff line change
@@ -736,24 +736,26 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
736736

737737
// Intrinsics are language primitives, not regular calls, so treat them separately.
738738
if let Some(intrinsic) = tcx.intrinsic(callee) {
739+
if !tcx.is_const_fn(callee) {
740+
// Non-const intrinsic.
741+
self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
742+
// If we allowed this, we're in miri-unleashed mode, so we might
743+
// as well skip the remaining checks.
744+
return;
745+
}
739746
// We use `intrinsic.const_stable` to determine if this can be safely exposed to
740747
// stable code, rather than `const_stable_indirect`. This is to make
741748
// `#[rustc_const_stable_indirect]` an attribute that is always safe to add.
742749
// We also ask is_safe_to_expose_on_stable_const_fn; this determines whether the intrinsic
743750
// fallback body is safe to expose on stable.
744751
let is_const_stable = intrinsic.const_stable
745752
|| (!intrinsic.must_be_overridden
746-
&& tcx.is_const_fn(callee)
747753
&& is_safe_to_expose_on_stable_const_fn(tcx, callee));
748754
match tcx.lookup_const_stability(callee) {
749755
None => {
750-
// Non-const intrinsic.
751-
self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
752-
}
753-
Some(ConstStability { feature: None, .. }) => {
754-
// Intrinsic does not need a separate feature gate (we rely on the
755-
// regular stability checker). However, we have to worry about recursive
756-
// const stability.
756+
// This doesn't need a separate const-stability check -- const-stability equals
757+
// regular stability, and regular stability is checked separately.
758+
// However, we *do* have to worry about *recursive* const stability.
757759
if !is_const_stable && self.enforce_recursive_const_stability() {
758760
self.dcx().emit_err(errors::UnmarkedIntrinsicExposed {
759761
span: self.span,
@@ -762,8 +764,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
762764
}
763765
}
764766
Some(ConstStability {
765-
feature: Some(feature),
766767
level: StabilityLevel::Unstable { .. },
768+
feature,
767769
..
768770
}) => {
769771
self.check_op(ops::IntrinsicUnstable {
@@ -802,7 +804,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
802804
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
803805
// All good.
804806
}
805-
None | Some(ConstStability { feature: None, .. }) => {
807+
None => {
806808
// This doesn't need a separate const-stability check -- const-stability equals
807809
// regular stability, and regular stability is checked separately.
808810
// However, we *do* have to worry about *recursive* const stability.
@@ -816,8 +818,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
816818
}
817819
}
818820
Some(ConstStability {
819-
feature: Some(feature),
820821
level: StabilityLevel::Unstable { implied_by: implied_feature, .. },
822+
feature,
821823
..
822824
}) => {
823825
// An unstable const fn with a feature gate.

compiler/rustc_const_eval/src/check_consts/mod.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,15 @@ pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> b
110110

111111
match tcx.lookup_const_stability(def_id) {
112112
None => {
113-
// Only marked functions can be trusted. Note that this may be a function in a
114-
// non-staged-API crate where no recursive checks were done!
115-
false
113+
// In a `staged_api` crate, we do enforce recursive const stability for all unmarked
114+
// functions, so we can trust local functions. But in another crate we don't know which
115+
// rules were applied, so we can't trust that.
116+
def_id.is_local() && tcx.features().staged_api()
116117
}
117118
Some(stab) => {
118-
// We consider things safe-to-expose if they are stable, if they don't have any explicit
119-
// const stability attribute, or if they are marked as `const_stable_indirect`.
120-
stab.is_const_stable() || stab.feature.is_none() || stab.const_stable_indirect
119+
// We consider things safe-to-expose if they are stable or if they are marked as
120+
// `const_stable_indirect`.
121+
stab.is_const_stable() || stab.const_stable_indirect
121122
}
122123
}
123124
}

compiler/rustc_expand/src/base.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -866,9 +866,7 @@ impl SyntaxExtension {
866866
})
867867
.unwrap_or_else(|| (None, helper_attrs));
868868
let stability = attr::find_stability(sess, attrs, span);
869-
// We set `is_const_fn` false to avoid getting any implicit const stability.
870-
let const_stability =
871-
attr::find_const_stability(sess, attrs, span, /* is_const_fn */ false);
869+
let const_stability = attr::find_const_stability(sess, attrs, span);
872870
let body_stability = attr::find_body_stability(sess, attrs);
873871
if let Some((_, sp)) = const_stability {
874872
sess.dcx().emit_err(errors::MacroConstStability {

0 commit comments

Comments
 (0)