about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2024-11-02 20:15:18 +0100
committerRalf Jung <post@ralfj.de>2024-11-10 10:01:27 +0100
commit686eeb83e9c6d7f70848cdf84f490f5c1aa3edd3 (patch)
tree74d0db972f0f0b0a1c75da8ff4361b8051d20124
parent668959740f97e7a22ae340742886d330ab63950f (diff)
downloadrust-686eeb83e9c6d7f70848cdf84f490f5c1aa3edd3.tar.gz
rust-686eeb83e9c6d7f70848cdf84f490f5c1aa3edd3.zip
honor rustc_const_stable_indirect in non-staged_api crate with -Zforce-unstable-if-unmarked
-rw-r--r--compiler/rustc_attr/src/builtin.rs20
-rw-r--r--compiler/rustc_const_eval/src/check_consts/mod.rs7
-rw-r--r--compiler/rustc_passes/src/stability.rs5
-rw-r--r--library/std/src/lib.rs5
-rw-r--r--tests/ui/consts/min_const_fn/auxiliary/unmarked_const_fn_crate.rs1
-rw-r--r--tests/ui/consts/min_const_fn/auxiliary/unstable_if_unmarked_const_fn_crate.rs8
-rw-r--r--tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.rs23
-rw-r--r--tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr28
-rw-r--r--tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs24
-rw-r--r--tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr37
10 files changed, 155 insertions, 3 deletions
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 2753ac529d1..3a7ea36f601 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -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(
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index dcdaafaecc2..3b2a79793ae 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -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())
     }
 
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index cd47c8ece60..264dd364b5b 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -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);
+                    }
                 }
             }
 
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 5b94f036248..53d5db02ecf 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -391,6 +391,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)]
diff --git a/tests/ui/consts/min_const_fn/auxiliary/unmarked_const_fn_crate.rs b/tests/ui/consts/min_const_fn/auxiliary/unmarked_const_fn_crate.rs
new file mode 100644
index 00000000000..aec92c5ae16
--- /dev/null
+++ b/tests/ui/consts/min_const_fn/auxiliary/unmarked_const_fn_crate.rs
@@ -0,0 +1 @@
+pub const fn just_a_fn() {}
diff --git a/tests/ui/consts/min_const_fn/auxiliary/unstable_if_unmarked_const_fn_crate.rs b/tests/ui/consts/min_const_fn/auxiliary/unstable_if_unmarked_const_fn_crate.rs
new file mode 100644
index 00000000000..f102902fce3
--- /dev/null
+++ b/tests/ui/consts/min_const_fn/auxiliary/unstable_if_unmarked_const_fn_crate.rs
@@ -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() {}
diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.rs b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.rs
new file mode 100644
index 00000000000..f03bfb81a14
--- /dev/null
+++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.rs
@@ -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() {
+
+}
diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr
new file mode 100644
index 00000000000..a655c0faab6
--- /dev/null
+++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr
@@ -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
+
diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs
new file mode 100644
index 00000000000..51811b14203
--- /dev/null
+++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs
@@ -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() };
+}
diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr
new file mode 100644
index 00000000000..d4ba0f9df2d
--- /dev/null
+++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr
@@ -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
+