Skip to content

Commit 686eeb8

Browse files
committed
honor rustc_const_stable_indirect in non-staged_api crate with -Zforce-unstable-if-unmarked
1 parent 6689597 commit 686eeb8

10 files changed

+155
-3
lines changed

compiler/rustc_attr/src/builtin.rs

+20
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,26 @@ pub fn find_const_stability(
381381
const_stab
382382
}
383383

384+
/// Calculates the const stability for a const function in a `-Zforce-unstable-if-unmarked` crate
385+
/// without the `staged_api` feature.
386+
pub fn unmarked_crate_const_stab(
387+
_sess: &Session,
388+
attrs: &[Attribute],
389+
regular_stab: Stability,
390+
) -> ConstStability {
391+
assert!(regular_stab.level.is_unstable());
392+
// The only attribute that matters here is `rustc_const_stable_indirect`.
393+
// We enforce recursive const stability rules for those functions.
394+
let const_stable_indirect =
395+
attrs.iter().any(|a| a.name_or_empty() == sym::rustc_const_stable_indirect);
396+
ConstStability {
397+
feature: Some(regular_stab.feature),
398+
const_stable_indirect,
399+
promotable: false,
400+
level: regular_stab.level,
401+
}
402+
}
403+
384404
/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`.
385405
/// Returns `None` if no stability attributes are found.
386406
pub fn find_body_stability(

compiler/rustc_const_eval/src/check_consts/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,11 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
5353
}
5454

5555
pub fn enforce_recursive_const_stability(&self) -> bool {
56-
// We can skip this if `staged_api` is not enabled, since in such crates
57-
// `lookup_const_stability` will always be `None`.
56+
// We can skip this if neither `staged_api` nor `-Zforrce-unstable-if-unmarked` are enabled,
57+
// since in such crates `lookup_const_stability` will always be `None`.
5858
self.const_kind == Some(hir::ConstContext::ConstFn)
59-
&& self.tcx.features().staged_api()
59+
&& (self.tcx.features().staged_api()
60+
|| self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked)
6061
&& is_safe_to_expose_on_stable_const_fn(self.tcx, self.def_id().to_def_id())
6162
}
6263

compiler/rustc_passes/src/stability.rs

+5
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
149149
if let Some(stab) = self.parent_stab {
150150
if inherit_deprecation.yes() && stab.is_unstable() {
151151
self.index.stab_map.insert(def_id, stab);
152+
if fn_sig.is_some_and(|s| s.header.is_const()) {
153+
let const_stab =
154+
attr::unmarked_crate_const_stab(self.tcx.sess, attrs, stab);
155+
self.index.const_stab_map.insert(def_id, const_stab);
156+
}
152157
}
153158
}
154159

library/std/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,11 @@
391391
#![feature(stdarch_internal)]
392392
// tidy-alphabetical-end
393393
//
394+
// Library features (crates without staged_api):
395+
// tidy-alphabetical-start
396+
#![feature(rustc_private)]
397+
// tidy-alphabetical-end
398+
//
394399
// Only for re-exporting:
395400
// tidy-alphabetical-start
396401
#![feature(assert_matches)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub const fn just_a_fn() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//@ compile-flags: -Zforce-unstable-if-unmarked
2+
3+
#![feature(rustc_attrs)]
4+
5+
pub const fn not_stably_const() {}
6+
7+
#[rustc_const_stable_indirect]
8+
pub const fn expose_on_stable() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@ aux-build:unstable_if_unmarked_const_fn_crate.rs
2+
//@ aux-build:unmarked_const_fn_crate.rs
3+
#![feature(staged_api, rustc_private)]
4+
#![stable(since="1.0.0", feature = "stable")]
5+
6+
extern crate unstable_if_unmarked_const_fn_crate;
7+
extern crate unmarked_const_fn_crate;
8+
9+
#[stable(feature = "rust1", since = "1.0.0")]
10+
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
11+
const fn stable_fn() {
12+
// This one is fine.
13+
unstable_if_unmarked_const_fn_crate::expose_on_stable();
14+
// This one is not.
15+
unstable_if_unmarked_const_fn_crate::not_stably_const();
16+
//~^ERROR: cannot use `#[feature(rustc_private)]`
17+
unmarked_const_fn_crate::just_a_fn();
18+
//~^ERROR: cannot be (indirectly) exposed to stable
19+
}
20+
21+
fn main() {
22+
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(rustc_private)]`
2+
--> $DIR/recursive_const_stab_unmarked_crate_imports.rs:15:5
3+
|
4+
LL | unstable_if_unmarked_const_fn_crate::not_stably_const();
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
8+
help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
9+
|
10+
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
11+
LL | const fn stable_fn() {
12+
|
13+
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
14+
|
15+
LL + #[rustc_allow_const_fn_unstable(rustc_private)]
16+
LL | const fn stable_fn() {
17+
|
18+
19+
error: `just_a_fn` cannot be (indirectly) exposed to stable
20+
--> $DIR/recursive_const_stab_unmarked_crate_imports.rs:17:5
21+
|
22+
LL | unmarked_const_fn_crate::just_a_fn();
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24+
|
25+
= help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
26+
27+
error: aborting due to 2 previous errors
28+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//@ compile-flags: -Zforce-unstable-if-unmarked
2+
//@ edition: 2021
3+
#![feature(const_async_blocks, rustc_attrs, rustc_private)]
4+
5+
pub const fn not_stably_const() {
6+
// We need to do something const-unstable here.
7+
// For now we use `async`, eventually we might have to add a auxiliary crate
8+
// as a dependency just to be sure we have something const-unstable.
9+
let _x = async { 15 };
10+
}
11+
12+
#[rustc_const_stable_indirect]
13+
pub const fn expose_on_stable() {
14+
// Calling `not_stably_const` here is *not* okay.
15+
not_stably_const();
16+
//~^ERROR: cannot use `#[feature(rustc_private)]`
17+
// Also directly using const-unstable things is not okay.
18+
let _x = async { 15 };
19+
//~^ERROR: cannot use `#[feature(const_async_blocks)]`
20+
}
21+
22+
fn main() {
23+
const { expose_on_stable() };
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(rustc_private)]`
2+
--> $DIR/recursive_const_stab_unstable_if_unmarked.rs:15:5
3+
|
4+
LL | not_stably_const();
5+
| ^^^^^^^^^^^^^^^^^^
6+
|
7+
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
8+
help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
9+
|
10+
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
11+
LL | pub const fn expose_on_stable() {
12+
|
13+
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
14+
|
15+
LL + #[rustc_allow_const_fn_unstable(rustc_private)]
16+
LL | pub const fn expose_on_stable() {
17+
|
18+
19+
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_async_blocks)]`
20+
--> $DIR/recursive_const_stab_unstable_if_unmarked.rs:18:14
21+
|
22+
LL | let _x = async { 15 };
23+
| ^^^^^^^^^^^^
24+
|
25+
help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
26+
|
27+
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
28+
LL | pub const fn expose_on_stable() {
29+
|
30+
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
31+
|
32+
LL + #[rustc_allow_const_fn_unstable(const_async_blocks)]
33+
LL | pub const fn expose_on_stable() {
34+
|
35+
36+
error: aborting due to 2 previous errors
37+

0 commit comments

Comments
 (0)