about summary refs log tree commit diff
path: root/tests/ui/traits
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2024-10-06 19:59:19 +0200
committerRalf Jung <post@ralfj.de>2024-10-25 20:31:40 +0200
commita0215d8e46aab41219dea0bb1cbaaf97dafe2f89 (patch)
treecb98c6fb900deceea7aa9f2d08455de383c45d02 /tests/ui/traits
parent45089ec19ebebec88bace6ec237244ff0eaa7ad3 (diff)
downloadrust-a0215d8e46aab41219dea0bb1cbaaf97dafe2f89.tar.gz
rust-a0215d8e46aab41219dea0bb1cbaaf97dafe2f89.zip
Re-do recursive const stability checks
Fundamentally, we have *three* disjoint categories of functions:
1. const-stable functions
2. private/unstable functions that are meant to be callable from const-stable functions
3. functions that can make use of unstable const features

This PR implements the following system:
- `#[rustc_const_stable]` puts functions in the first category. It may only be applied to `#[stable]` functions.
- `#[rustc_const_unstable]` by default puts functions in the third category. The new attribute `#[rustc_const_stable_indirect]` can be added to such a function to move it into the second category.
- `const fn` without a const stability marker are in the second category if they are still unstable. They automatically inherit the feature gate for regular calls, it can now also be used for const-calls.

Also, several holes in recursive const stability checking are being closed.
There's still one potential hole that is hard to avoid, which is when MIR
building automatically inserts calls to a particular function in stable
functions -- which happens in the panic machinery. Those need to *not* be
`rustc_const_unstable` (or manually get a `rustc_const_stable_indirect`) to be
sure they follow recursive const stability. But that's a fairly rare and special
case so IMO it's fine.

The net effect of this is that a `#[unstable]` or unmarked function can be
constified simply by marking it as `const fn`, and it will then be
const-callable from stable `const fn` and subject to recursive const stability
requirements. If it is publicly reachable (which implies it cannot be unmarked),
it will be const-unstable under the same feature gate. Only if the function ever
becomes `#[stable]` does it need a `#[rustc_const_unstable]` or
`#[rustc_const_stable]` marker to decide if this should also imply
const-stability.

Adding `#[rustc_const_unstable]` is only needed for (a) functions that need to
use unstable const lang features (including intrinsics), or (b) `#[stable]`
functions that are not yet intended to be const-stable. Adding
`#[rustc_const_stable]` is only needed for functions that are actually meant to
be directly callable from stable const code. `#[rustc_const_stable_indirect]` is
used to mark intrinsics as const-callable and for `#[rustc_const_unstable]`
functions that are actually called from other, exposed-on-stable `const fn`. No
other attributes are required.
Diffstat (limited to 'tests/ui/traits')
-rw-r--r--tests/ui/traits/const-traits/auxiliary/staged-api.rs9
-rw-r--r--tests/ui/traits/const-traits/effects/minicore.rs2
-rw-r--r--tests/ui/traits/const-traits/issue-79450.rs1
-rw-r--r--tests/ui/traits/const-traits/issue-79450.stderr2
-rw-r--r--tests/ui/traits/const-traits/staged-api.rs34
-rw-r--r--tests/ui/traits/const-traits/staged-api.stable.stderr56
-rw-r--r--tests/ui/traits/const-traits/staged-api.unstable.stderr102
7 files changed, 166 insertions, 40 deletions
diff --git a/tests/ui/traits/const-traits/auxiliary/staged-api.rs b/tests/ui/traits/const-traits/auxiliary/staged-api.rs
index 986165ef91e..bb591321b84 100644
--- a/tests/ui/traits/const-traits/auxiliary/staged-api.rs
+++ b/tests/ui/traits/const-traits/auxiliary/staged-api.rs
@@ -19,3 +19,12 @@ pub struct Unstable;
 impl const MyTrait for Unstable {
     fn func() {}
 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Unstable2;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "unstable2", issue = "none")]
+impl const MyTrait for Unstable2 {
+    fn func() {}
+}
diff --git a/tests/ui/traits/const-traits/effects/minicore.rs b/tests/ui/traits/const-traits/effects/minicore.rs
index a756f4d9f6c..1f0d22eeb38 100644
--- a/tests/ui/traits/const-traits/effects/minicore.rs
+++ b/tests/ui/traits/const-traits/effects/minicore.rs
@@ -515,7 +515,7 @@ trait StructuralPartialEq {}
 
 const fn drop<T: ~const Destruct>(_: T) {}
 
-#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
+#[rustc_const_stable_indirect]
 #[rustc_intrinsic_must_be_overridden]
 #[rustc_intrinsic]
 const fn const_eval_select<ARG: Tuple, F, G, RET>(
diff --git a/tests/ui/traits/const-traits/issue-79450.rs b/tests/ui/traits/const-traits/issue-79450.rs
index b8b9e07b3bd..cdefebc87d6 100644
--- a/tests/ui/traits/const-traits/issue-79450.rs
+++ b/tests/ui/traits/const-traits/issue-79450.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -Znext-solver
 #![allow(incomplete_features)]
-#![feature(const_fmt_arguments_new)]
 #![feature(const_trait_impl, effects)]
 
 #[const_trait]
diff --git a/tests/ui/traits/const-traits/issue-79450.stderr b/tests/ui/traits/const-traits/issue-79450.stderr
index 9e6348d37ed..49f380c1a2b 100644
--- a/tests/ui/traits/const-traits/issue-79450.stderr
+++ b/tests/ui/traits/const-traits/issue-79450.stderr
@@ -1,5 +1,5 @@
 error[E0015]: cannot call non-const fn `_print` in constant functions
-  --> $DIR/issue-79450.rs:11:9
+  --> $DIR/issue-79450.rs:10:9
    |
 LL |         println!("lul");
    |         ^^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/const-traits/staged-api.rs b/tests/ui/traits/const-traits/staged-api.rs
index f87e723472a..59fe6d52d5d 100644
--- a/tests/ui/traits/const-traits/staged-api.rs
+++ b/tests/ui/traits/const-traits/staged-api.rs
@@ -2,6 +2,7 @@
 //@ compile-flags: -Znext-solver
 
 #![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file.
+#![cfg_attr(unstable, feature(local_feature))]
 #![feature(const_trait_impl, effects)]
 #![allow(incomplete_features)]
 #![feature(staged_api)]
@@ -16,8 +17,8 @@ use staged_api::*;
 pub struct Foo;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))]
-#[cfg_attr(stable, rustc_const_stable(feature = "foo", since = "1.0.0"))]
+#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))]
+#[cfg_attr(stable, rustc_const_stable(feature = "local_feature", since = "1.0.0"))]
 impl const MyTrait for Foo {
     //[stable]~^ ERROR trait implementations cannot be const stable yet
     fn func() {}
@@ -32,32 +33,43 @@ fn non_const_context() {
 #[unstable(feature = "none", issue = "none")]
 const fn const_context() {
     Unstable::func();
-    //[stable]~^ ERROR not yet stable as a const fn
+    //[unstable]~^ ERROR cannot use `#[feature(unstable)]`
+    //[stable]~^^ ERROR not yet stable as a const fn
     Foo::func();
-    //[unstable]~^ ERROR not yet stable as a const fn
-    // ^ fails, because the `foo` feature is not active
+    //[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
+    //[stable]~^^ cannot be (indirectly) exposed to stable
+    // We get the error on `stable` since this is a trait function.
+    Unstable2::func();
+    //~^ ERROR not yet stable as a const fn
+    // ^ fails, because the `unstable2` feature is not active
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))]
+#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))]
 pub const fn const_context_not_const_stable() {
     //[stable]~^ ERROR function has missing const stability attribute
     Unstable::func();
     //[stable]~^ ERROR not yet stable as a const fn
     Foo::func();
-    //[unstable]~^ ERROR not yet stable as a const fn
-    // ^ fails, because the `foo` feature is not active
+    //[stable]~^ cannot be (indirectly) exposed to stable
+    // We get the error on `stable` since this is a trait function.
+    Unstable2::func();
+    //~^ ERROR not yet stable as a const fn
+    // ^ fails, because the `unstable2` feature is not active
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "cheese", since = "1.0.0")]
 const fn stable_const_context() {
     Unstable::func();
-    //~^ ERROR not yet stable as a const fn
+    //[unstable]~^ ERROR cannot use `#[feature(unstable)]`
+    //[stable]~^^ ERROR not yet stable as a const fn
     Foo::func();
-    //[unstable]~^ ERROR not yet stable as a const fn
+    //[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
+    //[stable]~^^ cannot be (indirectly) exposed to stable
+    // We get the error on `stable` since this is a trait function.
     const_context_not_const_stable()
-    //[unstable]~^ ERROR not yet stable as a const fn
+    //[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/staged-api.stable.stderr b/tests/ui/traits/const-traits/staged-api.stable.stderr
index 6c07a253f5b..40045081f93 100644
--- a/tests/ui/traits/const-traits/staged-api.stable.stderr
+++ b/tests/ui/traits/const-traits/staged-api.stable.stderr
@@ -1,5 +1,5 @@
 error: trait implementations cannot be const stable yet
-  --> $DIR/staged-api.rs:21:1
+  --> $DIR/staged-api.rs:22:1
    |
 LL | / impl const MyTrait for Foo {
 LL | |
@@ -10,40 +10,80 @@ LL | | }
    = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
 
 error: function has missing const stability attribute
-  --> $DIR/staged-api.rs:43:1
+  --> $DIR/staged-api.rs:49:1
    |
 LL | / pub const fn const_context_not_const_stable() {
 LL | |
 LL | |     Unstable::func();
 LL | |
 ...  |
-LL | |     // ^ fails, because the `foo` feature is not active
+LL | |     // ^ fails, because the `unstable2` feature is not active
 LL | | }
    | |_^
 
 error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:34:5
+  --> $DIR/staged-api.rs:35:5
    |
 LL |     Unstable::func();
    |     ^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(unstable)]` to the crate attributes to enable
 
+error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable
+  --> $DIR/staged-api.rs:38:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+   = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
+
+error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:42:5
+   |
+LL |     Unstable2::func();
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable2)]` to the crate attributes to enable
+
 error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:45:5
+  --> $DIR/staged-api.rs:51:5
    |
 LL |     Unstable::func();
    |     ^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(unstable)]` to the crate attributes to enable
 
+error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable
+  --> $DIR/staged-api.rs:53:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+   = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
+
+error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:56:5
+   |
+LL |     Unstable2::func();
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable2)]` to the crate attributes to enable
+
 error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:55:5
+  --> $DIR/staged-api.rs:64:5
    |
 LL |     Unstable::func();
    |     ^^^^^^^^^^^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+
+error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable
+  --> $DIR/staged-api.rs:67:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+   = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
 
-error: aborting due to 5 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/tests/ui/traits/const-traits/staged-api.unstable.stderr b/tests/ui/traits/const-traits/staged-api.unstable.stderr
index 1c772f13dd5..64b3a8ab19f 100644
--- a/tests/ui/traits/const-traits/staged-api.unstable.stderr
+++ b/tests/ui/traits/const-traits/staged-api.unstable.stderr
@@ -1,42 +1,108 @@
-error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:36:5
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
+  --> $DIR/staged-api.rs:35:5
    |
-LL |     Foo::func();
-   |     ^^^^^^^^^^^
+LL |     Unstable::func();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = 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 const_context() {
+   |
+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(unstable)]
+LL | const fn const_context() {
    |
-   = help: add `#![feature(foo)]` to the crate attributes to enable
 
-error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:47:5
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
+  --> $DIR/staged-api.rs:38:5
    |
 LL |     Foo::func();
    |     ^^^^^^^^^^^
    |
-   = help: add `#![feature(foo)]` to the crate attributes to enable
+   = 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 const_context() {
+   |
+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(local_feature)]
+LL | const fn const_context() {
+   |
+
+error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:42:5
+   |
+LL |     Unstable2::func();
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable2)]` to the crate attributes to enable
 
-error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:55:5
+error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:56:5
+   |
+LL |     Unstable2::func();
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable2)]` to the crate attributes to enable
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
+  --> $DIR/staged-api.rs:64:5
    |
 LL |     Unstable::func();
    |     ^^^^^^^^^^^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = 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_const_context() {
+   |
+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(unstable)]
+LL | const fn stable_const_context() {
+   |
 
-error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:57:5
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
+  --> $DIR/staged-api.rs:67:5
    |
 LL |     Foo::func();
    |     ^^^^^^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = 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_const_context() {
+   |
+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(local_feature)]
+LL | const fn stable_const_context() {
+   |
 
-error: `const_context_not_const_stable` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:59:5
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
+  --> $DIR/staged-api.rs:71:5
    |
 LL |     const_context_not_const_stable()
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = 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_const_context() {
+   |
+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(local_feature)]
+LL | const fn stable_const_context() {
+   |
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors