Skip to content

Commit

Permalink
honor rustc_const_stable_indirect in non-staged_api crate with -Zforc…
Browse files Browse the repository at this point in the history
…e-unstable-if-unmarked
  • Loading branch information
RalfJung committed Nov 3, 2024
1 parent d60ea80 commit 144bd4e
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 3 deletions.
20 changes: 20 additions & 0 deletions compiler/rustc_attr/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,26 @@ pub fn find_const_stability(
const_stab
}

/// Calculates the const stability for a const function in a `-Zforce-unstable-if-unmarked` crate
/// without the `staged_api` feature.
pub fn unmarked_crate_const_stab(
_sess: &Session,
attrs: &[Attribute],
regular_stab: Stability,
) -> ConstStability {
assert!(regular_stab.level.is_unstable());
// The only attribute that matters here is `rustc_const_stable_indirect`.
// We enforce recursive const stability rules for those functions.
let const_stable_indirect =
attrs.iter().any(|a| a.name_or_empty() == sym::rustc_const_stable_indirect);
ConstStability {
feature: Some(regular_stab.feature),
const_stable_indirect,
promotable: false,
level: regular_stab.level,
}
}

/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`.
/// Returns `None` if no stability attributes are found.
pub fn find_body_stability(
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_const_eval/src/check_consts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
}

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

Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_passes/src/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
if let Some(stab) = self.parent_stab {
if inherit_deprecation.yes() && stab.is_unstable() {
self.index.stab_map.insert(def_id, stab);
if fn_sig.is_some_and(|s| s.header.is_const()) {
let const_stab =
attr::unmarked_crate_const_stab(self.tcx.sess, attrs, stab);
self.index.const_stab_map.insert(def_id, const_stab);
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,11 @@
#![feature(stdarch_internal)]
// tidy-alphabetical-end
//
// Library features (crates without staged_api):
// tidy-alphabetical-start
#![feature(rustc_private)]
// tidy-alphabetical-end
//
// Only for re-exporting:
// tidy-alphabetical-start
#![feature(assert_matches)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub const fn just_a_fn() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//@ compile-flags: -Zforce-unstable-if-unmarked

#![feature(rustc_attrs)]

pub const fn not_stably_const() {}

#[rustc_const_stable_indirect]
pub const fn expose_on_stable() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//@ aux-build:unstable_if_unmarked_const_fn_crate.rs
//@ aux-build:unmarked_const_fn_crate.rs
#![feature(staged_api, rustc_private)]
#![stable(since="1.0.0", feature = "stable")]

extern crate unstable_if_unmarked_const_fn_crate;
extern crate unmarked_const_fn_crate;

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
const fn stable_fn() {
// This one is fine.
unstable_if_unmarked_const_fn_crate::expose_on_stable();
// This one is not.
unstable_if_unmarked_const_fn_crate::not_stably_const();
//~^ERROR: cannot use `#[feature(rustc_private)]`
unmarked_const_fn_crate::just_a_fn();
//~^ERROR: cannot be (indirectly) exposed to stable
}

fn main() {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(rustc_private)]`
--> $DIR/recursive_const_stab_unmarked_crate_imports.rs:15:5
|
LL | unstable_if_unmarked_const_fn_crate::not_stably_const();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
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)
|
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
LL | const fn stable_fn() {
|
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
LL + #[rustc_allow_const_fn_unstable(rustc_private)]
LL | const fn stable_fn() {
|

error: `just_a_fn` cannot be (indirectly) exposed to stable
--> $DIR/recursive_const_stab_unmarked_crate_imports.rs:17:5
|
LL | unmarked_const_fn_crate::just_a_fn();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`

error: aborting due to 2 previous errors

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//@ compile-flags: -Zforce-unstable-if-unmarked
//@ edition: 2021
#![feature(const_async_blocks, rustc_attrs, rustc_private)]

pub const fn not_stably_const() {
// We need to do something const-unstable here.
// For now we use `async`, eventually we might have to add a auxiliary crate
// as a dependency just to be sure we have something const-unstable.
let _x = async { 15 };
}

#[rustc_const_stable_indirect]
pub const fn expose_on_stable() {
// Calling `not_stably_const` here is *not* okay.
not_stably_const();
//~^ERROR: cannot use `#[feature(rustc_private)]`
// Also directly using const-unstable things is not okay.
let _x = async { 15 };
//~^ERROR: cannot use `#[feature(const_async_blocks)]`
}

fn main() {
const { expose_on_stable() };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(rustc_private)]`
--> $DIR/recursive_const_stab_unstable_if_unmarked.rs:15:5
|
LL | not_stably_const();
| ^^^^^^^^^^^^^^^^^^
|
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
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)
|
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
LL | pub const fn expose_on_stable() {
|
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
LL + #[rustc_allow_const_fn_unstable(rustc_private)]
LL | pub const fn expose_on_stable() {
|

error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_async_blocks)]`
--> $DIR/recursive_const_stab_unstable_if_unmarked.rs:18:14
|
LL | let _x = async { 15 };
| ^^^^^^^^^^^^
|
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)
|
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
LL | pub const fn expose_on_stable() {
|
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
LL + #[rustc_allow_const_fn_unstable(const_async_blocks)]
LL | pub const fn expose_on_stable() {
|

error: aborting due to 2 previous errors

0 comments on commit 144bd4e

Please sign in to comment.