Skip to content

Commit b630e50

Browse files
committed
fix gaps on recursive const stability check, and add rustc_const_stable_indirect attribute to mark unstable fn as recursively checked
1 parent f559d61 commit b630e50

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+829
-298
lines changed

compiler/rustc_attr/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ attr_non_ident_feature =
9191
attr_rustc_allowed_unstable_pairing =
9292
`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
9393
94+
attr_rustc_const_stable_indirect_pairing =
95+
`const_stable_indirect` attribute does not make sense on `rustc_const_stable` function, its behavior is already implied
96+
9497
attr_rustc_promotable_pairing =
9598
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
9699

compiler/rustc_attr/src/builtin.rs

+56-7
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;
2019
use rustc_span::hygiene::Transparency;
2120
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,7 +92,13 @@ impl Stability {
9292
#[derive(HashStable_Generic)]
9393
pub struct ConstStability {
9494
pub level: StabilityLevel,
95-
pub feature: Symbol,
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`.
97+
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,
96102
/// whether the function has a `#[rustc_promotable]` attribute
97103
pub promotable: bool,
98104
}
@@ -275,10 +281,12 @@ pub fn find_const_stability(
275281
) -> Option<(ConstStability, Span)> {
276282
let mut const_stab: Option<(ConstStability, Span)> = None;
277283
let mut promotable = false;
284+
let mut const_stable_indirect = false;
278285

279286
for attr in attrs {
280287
match attr.name_or_empty() {
281288
sym::rustc_promotable => promotable = true,
289+
sym::rustc_const_stable_indirect => const_stable_indirect = true,
282290
sym::rustc_const_unstable => {
283291
if const_stab.is_some() {
284292
sess.dcx()
@@ -287,8 +295,15 @@ pub fn find_const_stability(
287295
}
288296

289297
if let Some((feature, level)) = parse_unstability(sess, attr) {
290-
const_stab =
291-
Some((ConstStability { level, feature, promotable: false }, attr.span));
298+
const_stab = Some((
299+
ConstStability {
300+
level,
301+
feature: Some(feature),
302+
safe_to_expose_on_stable: false,
303+
promotable: false,
304+
},
305+
attr.span,
306+
));
292307
}
293308
}
294309
sym::rustc_const_stable => {
@@ -298,15 +313,22 @@ pub fn find_const_stability(
298313
break;
299314
}
300315
if let Some((feature, level)) = parse_stability(sess, attr) {
301-
const_stab =
302-
Some((ConstStability { level, feature, promotable: false }, attr.span));
316+
const_stab = Some((
317+
ConstStability {
318+
level,
319+
feature: Some(feature),
320+
safe_to_expose_on_stable: true,
321+
promotable: false,
322+
},
323+
attr.span,
324+
));
303325
}
304326
}
305327
_ => {}
306328
}
307329
}
308330

309-
// Merge the const-unstable info into the stability info
331+
// Merge promotable and not_exposed_on_stable into stability info
310332
if promotable {
311333
match &mut const_stab {
312334
Some((stab, _)) => stab.promotable = promotable,
@@ -317,6 +339,33 @@ pub fn find_const_stability(
317339
}
318340
}
319341
}
342+
if const_stable_indirect {
343+
match &mut const_stab {
344+
Some((stab, _)) => {
345+
if stab.is_const_unstable() {
346+
stab.safe_to_expose_on_stable = true;
347+
} else {
348+
_ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
349+
span: item_sp,
350+
})
351+
}
352+
}
353+
_ => {
354+
let c = ConstStability {
355+
feature: None,
356+
safe_to_expose_on_stable: true,
357+
promotable: false,
358+
level: StabilityLevel::Unstable {
359+
reason: UnstableReason::Default,
360+
issue: None,
361+
is_soft: false,
362+
implied_by: None,
363+
},
364+
};
365+
const_stab = Some((c, DUMMY_SP));
366+
}
367+
}
368+
}
320369

321370
const_stab
322371
}

compiler/rustc_attr/src/session_diagnostics.rs

+7
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,13 @@ pub(crate) struct RustcPromotablePairing {
318318
pub span: Span,
319319
}
320320

321+
#[derive(Diagnostic)]
322+
#[diag(attr_rustc_const_stable_indirect_pairing)]
323+
pub(crate) struct RustcConstStableIndirectPairing {
324+
#[primary_span]
325+
pub span: Span,
326+
}
327+
321328
#[derive(Diagnostic)]
322329
#[diag(attr_rustc_allowed_unstable_pairing, code = E0789)]
323330
pub(crate) struct RustcAllowedUnstablePairing {

compiler/rustc_const_eval/messages.ftl

+8-6
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ const_eval_const_context = {$kind ->
4141
*[other] {""}
4242
}
4343
44-
const_eval_const_stable = const-stable functions can only call other const-stable functions
45-
4644
const_eval_copy_nonoverlapping_overlapping =
4745
`copy_nonoverlapping` called on overlapping ranges
4846
@@ -396,17 +394,21 @@ const_eval_uninhabited_enum_variant_read =
396394
read discriminant of an uninhabited enum variant
397395
const_eval_uninhabited_enum_variant_written =
398396
writing discriminant of an uninhabited enum variant
397+
398+
const_eval_unmarked_const_fn_exposed = `{$def_path}` cannot be (indirectly) exposed to stable
399+
.help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
400+
399401
const_eval_unreachable = entering unreachable code
400402
const_eval_unreachable_unwind =
401403
unwinding past a stack frame that does not allow unwinding
402404
403405
const_eval_unsized_local = unsized locals are not supported
404406
const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
405407
406-
const_eval_unstable_in_stable =
407-
const-stable function cannot use `#[feature({$gate})]`
408-
.unstable_sugg = if the function is not (yet) meant to be stable, make this function unstably const
409-
.bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval)
408+
const_eval_unstable_in_stable_exposed =
409+
const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]`
410+
.unstable_sugg = if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this what you probably want to do)
411+
.bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
410412
411413
const_eval_unterminated_c_string =
412414
reading a null-terminated string starting at {$pointer} with no null found before end of allocation

0 commit comments

Comments
 (0)