diff options
| author | Ralf Jung <post@ralfj.de> | 2024-10-06 19:59:19 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2024-10-25 20:31:40 +0200 |
| commit | a0215d8e46aab41219dea0bb1cbaaf97dafe2f89 (patch) | |
| tree | cb98c6fb900deceea7aa9f2d08455de383c45d02 /tests/ui/traits | |
| parent | 45089ec19ebebec88bace6ec237244ff0eaa7ad3 (diff) | |
| download | rust-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.rs | 9 | ||||
| -rw-r--r-- | tests/ui/traits/const-traits/effects/minicore.rs | 2 | ||||
| -rw-r--r-- | tests/ui/traits/const-traits/issue-79450.rs | 1 | ||||
| -rw-r--r-- | tests/ui/traits/const-traits/issue-79450.stderr | 2 | ||||
| -rw-r--r-- | tests/ui/traits/const-traits/staged-api.rs | 34 | ||||
| -rw-r--r-- | tests/ui/traits/const-traits/staged-api.stable.stderr | 56 | ||||
| -rw-r--r-- | tests/ui/traits/const-traits/staged-api.unstable.stderr | 102 |
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 |
