about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-10-25 23:29:40 +0000
committerbors <bors@rust-lang.org>2024-10-25 23:29:40 +0000
commit54761cb3e819eb5ae94774fd292f9e58372b1a0c (patch)
tree9f30c76a151fc4ae3eb531b755b4db4cd79ac470 /tests
parentc1db4dc24267a707409c9bf2e67cf3c7323975c8 (diff)
parent8849ac6042770500db91aca860ec8d86af2c74a3 (diff)
downloadrust-54761cb3e819eb5ae94774fd292f9e58372b1a0c.tar.gz
rust-54761cb3e819eb5ae94774fd292f9e58372b1a0c.zip
Auto merge of #131349 - RalfJung:const-stability-checks, r=compiler-errors
Const stability checks v2

The const stability system has served us well ever since `const fn` were first stabilized. It's main feature is that it enforces *recursive* validity -- a stable const fn cannot internally make use of unstable const features without an explicit marker in the form of `#[rustc_allow_const_fn_unstable]`. This is done to make sure that we don't accidentally expose unstable const features on stable in a way that would be hard to take back. As part of this, it is enforced that a `#[rustc_const_stable]` can only call `#[rustc_const_stable]` functions. However, some problems have been coming up with increased usage:
- It is baffling that we have to mark private or even unstable functions as `#[rustc_const_stable]` when they are used as helpers in regular stable `const fn`, and often people will rather add `#[rustc_allow_const_fn_unstable]` instead which was not our intention.
- The system has several gaping holes: a private `const fn` without stability attributes whose inherited stability (walking up parent modules) is `#[stable]` is allowed to call *arbitrary* unstable const operations, but can itself be called from stable `const fn`. Similarly, `#[allow_internal_unstable]` on a macro completely bypasses the recursive nature of the check.

Fundamentally, the problem is that we have *three* disjoint categories of functions, and not enough attributes to distinguish them:
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

Functions in the first two categories cannot use unstable const features and they can only call functions from the first two categories.

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, all the holes mentioned above have been 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 be manually marked `#[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.

Also see the updated dev-guide at https://github.com/rust-lang/rustc-dev-guide/pull/2098.

I think in the future we may want to tweak this further, so that in the hopefully common case where a public function's const-stability just exactly mirrors its regular stability, we never have to add any attribute. But right now, once the function is stable this requires `#[rustc_const_stable]`.

### Open question

There is one point I could see we might want to do differently, and that is putting `#[rustc_const_unstable]`  functions (but not intrinsics) in category 2 by default, and requiring an extra attribute for `#[rustc_const_not_exposed_on_stable]` or so. This would require a bunch of extra annotations, but would have the advantage that turning a `#[rustc_const_unstable]` into `#[rustc_const_stable]`  will never change the way the function is const-checked. Currently, we often discover in the const stabilization PR that a function needs some other unstable const things, and then we rush to quickly deal with that. In this alternative universe, we'd work towards getting rid of the `rustc_const_not_exposed_on_stable` before stabilization, and once that is done stabilization becomes a trivial matter. `#[rustc_const_stable_indirect]` would then only be used for intrinsics.

I think I like this idea, but might want to do it in a follow-up PR, as it will need a whole bunch of annotations in the standard library. Also, we probably want to convert all const intrinsics to the "new" form (`#[rustc_intrinsic]` instead of an `extern` block) before doing this to avoid having to deal with two different ways of declaring intrinsics.

Cc `@rust-lang/wg-const-eval` `@rust-lang/libs-api`
Part of https://github.com/rust-lang/rust/issues/129815 (but not finished since this is not yet sufficient to safely let us expose `const fn` from hashbrown)
Fixes https://github.com/rust-lang/rust/issues/131073 by making it so that const-stable functions are always stable

try-job: test-various
Diffstat (limited to 'tests')
-rw-r--r--tests/rustdoc/const-display.rs6
-rw-r--r--tests/ui/borrowck/issue-64453.rs1
-rw-r--r--tests/ui/borrowck/issue-64453.stderr13
-rw-r--r--tests/ui/consts/auxiliary/unstable_but_const_stable.rs13
-rw-r--r--tests/ui/consts/auxiliary/unstable_intrinsic.rs26
-rw-r--r--tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs4
-rw-r--r--tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr14
-rw-r--r--tests/ui/consts/const-eval/simd/insert_extract.rs3
-rw-r--r--tests/ui/consts/const-unstable-intrinsic.rs76
-rw-r--r--tests/ui/consts/const-unstable-intrinsic.stderr127
-rw-r--r--tests/ui/consts/copy-intrinsic.rs2
-rw-r--r--tests/ui/consts/copy-intrinsic.stderr8
-rw-r--r--tests/ui/consts/intrinsic_without_const_stab.rs17
-rw-r--r--tests/ui/consts/intrinsic_without_const_stab.stderr11
-rw-r--r--tests/ui/consts/intrinsic_without_const_stab_fail.rs15
-rw-r--r--tests/ui/consts/intrinsic_without_const_stab_fail.stderr11
-rw-r--r--tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs34
-rw-r--r--tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr108
-rw-r--r--tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs8
-rw-r--r--tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr46
-rw-r--r--tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs8
-rw-r--r--tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr46
-rw-r--r--tests/ui/consts/rustc-const-stability-require-const.rs32
-rw-r--r--tests/ui/consts/rustc-const-stability-require-const.stderr38
-rw-r--r--tests/ui/consts/unstable-const-stable.rs14
-rw-r--r--tests/ui/consts/unstable-const-stable.stderr43
-rw-r--r--tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr22
-rw-r--r--tests/ui/intrinsics/const-eval-select-stability.rs2
-rw-r--r--tests/ui/intrinsics/const-eval-select-stability.stderr13
-rw-r--r--tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs1
-rw-r--r--tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr10
-rw-r--r--tests/ui/stability-attribute/missing-const-stability.rs13
-rw-r--r--tests/ui/stability-attribute/missing-const-stability.stderr10
-rw-r--r--tests/ui/target-feature/feature-hierarchy.rs1
-rw-r--r--tests/ui/target-feature/no-llvm-leaks.rs1
-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
42 files changed, 716 insertions, 287 deletions
diff --git a/tests/rustdoc/const-display.rs b/tests/rustdoc/const-display.rs
index a71825d883d..bc4270c421d 100644
--- a/tests/rustdoc/const-display.rs
+++ b/tests/rustdoc/const-display.rs
@@ -89,10 +89,4 @@ impl Bar {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const2", since = "1.2.0")]
     pub const fn stable_impl() -> u32 { 42 }
-
-    // Show const-stability even for unstable functions.
-    //@ matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.3.0$'
-    #[unstable(feature = "foo2", issue = "none")]
-    #[rustc_const_stable(feature = "const3", since = "1.3.0")]
-    pub const fn const_stable_unstable() -> u32 { 42 }
 }
diff --git a/tests/ui/borrowck/issue-64453.rs b/tests/ui/borrowck/issue-64453.rs
index 33d55be5812..5f1f35d6ca9 100644
--- a/tests/ui/borrowck/issue-64453.rs
+++ b/tests/ui/borrowck/issue-64453.rs
@@ -3,7 +3,6 @@ struct Value;
 
 static settings_dir: String = format!("");
 //~^ ERROR cannot call non-const fn
-//~| ERROR is not yet stable as a const
 
 fn from_string(_: String) -> Value {
     Value
diff --git a/tests/ui/borrowck/issue-64453.stderr b/tests/ui/borrowck/issue-64453.stderr
index e671817633b..98b05ead649 100644
--- a/tests/ui/borrowck/issue-64453.stderr
+++ b/tests/ui/borrowck/issue-64453.stderr
@@ -1,12 +1,3 @@
-error: `Arguments::<'a>::new_const` is not yet stable as a const fn
-  --> $DIR/issue-64453.rs:4:31
-   |
-LL | static settings_dir: String = format!("");
-   |                               ^^^^^^^^^^^
-   |
-   = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable
-   = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
 error[E0015]: cannot call non-const fn `format` in statics
   --> $DIR/issue-64453.rs:4:31
    |
@@ -18,7 +9,7 @@ LL | static settings_dir: String = format!("");
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0507]: cannot move out of static item `settings_dir`
-  --> $DIR/issue-64453.rs:14:37
+  --> $DIR/issue-64453.rs:13:37
    |
 LL |     let settings_data = from_string(settings_dir);
    |                                     ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait
@@ -28,7 +19,7 @@ help: consider cloning the value if the performance cost is acceptable
 LL |     let settings_data = from_string(settings_dir.clone());
    |                                                 ++++++++
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0015, E0507.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/auxiliary/unstable_but_const_stable.rs b/tests/ui/consts/auxiliary/unstable_but_const_stable.rs
deleted file mode 100644
index 88044b0272c..00000000000
--- a/tests/ui/consts/auxiliary/unstable_but_const_stable.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#![feature(staged_api, rustc_attrs, intrinsics)]
-#![stable(since="1.0.0", feature = "stable")]
-
-extern "rust-intrinsic" {
-    #[unstable(feature = "unstable", issue = "42")]
-    #[rustc_const_stable(feature = "stable", since = "1.0.0")]
-    #[rustc_nounwind]
-    pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
-}
-
-#[unstable(feature = "unstable", issue = "42")]
-#[rustc_const_stable(feature = "stable", since = "1.0.0")]
-pub const fn some_unstable_fn() {}
diff --git a/tests/ui/consts/auxiliary/unstable_intrinsic.rs b/tests/ui/consts/auxiliary/unstable_intrinsic.rs
new file mode 100644
index 00000000000..edef499dbb1
--- /dev/null
+++ b/tests/ui/consts/auxiliary/unstable_intrinsic.rs
@@ -0,0 +1,26 @@
+#![feature(staged_api, rustc_attrs, intrinsics)]
+#![stable(since="1.0.0", feature = "stable")]
+
+#[stable(since="1.0.0", feature = "stable")]
+pub mod old_way {
+    extern "rust-intrinsic" {
+        #[unstable(feature = "unstable", issue = "42")]
+        pub fn size_of_val<T>(x: *const T) -> usize;
+
+        #[unstable(feature = "unstable", issue = "42")]
+        #[rustc_const_unstable(feature = "unstable", issue = "42")]
+        pub fn min_align_of_val<T>(x: *const T) -> usize;
+    }
+}
+
+#[stable(since="1.0.0", feature = "stable")]
+pub mod new_way {
+    #[unstable(feature = "unstable", issue = "42")]
+    #[rustc_intrinsic]
+    pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
+
+    #[unstable(feature = "unstable", issue = "42")]
+    #[rustc_const_unstable(feature = "unstable", issue = "42")]
+    #[rustc_intrinsic]
+    pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 }
+}
diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
index 4b3cf70739c..6c93c0e63b6 100644
--- a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
+++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
@@ -3,7 +3,7 @@
             we're apparently really bad at it",
             issue = "none")]
 
-#![feature(staged_api)]
+#![feature(staged_api, foo)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature="foo", issue = "none")]
@@ -11,7 +11,7 @@ const fn foo() -> u32 { 42 }
 
 fn meh() -> u32 { 42 }
 
-const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn
+const fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]`
 
 fn a() {
     let _: &'static u32 = &foo(); //~ ERROR temporary value dropped while borrowed
diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
index 2e697b219c5..1de1c78faf6 100644
--- a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
+++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
@@ -1,10 +1,20 @@
-error: `foo` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
   --> $DIR/dont_promote_unstable_const_fn.rs:14:25
    |
 LL | const fn bar() -> u32 { foo() }
    |                         ^^^^^
    |
-   = 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 bar() -> u32 { foo() }
+   |
+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(foo)]
+LL | const fn bar() -> u32 { foo() }
+   |
 
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/dont_promote_unstable_const_fn.rs:17:28
diff --git a/tests/ui/consts/const-eval/simd/insert_extract.rs b/tests/ui/consts/const-eval/simd/insert_extract.rs
index f4f25327aaf..57d4b4888ca 100644
--- a/tests/ui/consts/const-eval/simd/insert_extract.rs
+++ b/tests/ui/consts/const-eval/simd/insert_extract.rs
@@ -11,8 +11,11 @@
 #[repr(simd)] struct f32x4([f32; 4]);
 
 extern "rust-intrinsic" {
+    #[stable(feature = "foo", since = "1.3.37")]
     #[rustc_const_stable(feature = "foo", since = "1.3.37")]
     fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
+
+    #[stable(feature = "foo", since = "1.3.37")]
     #[rustc_const_stable(feature = "foo", since = "1.3.37")]
     fn simd_extract<T, U>(x: T, idx: u32) -> U;
 }
diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs
new file mode 100644
index 00000000000..050abc6dd46
--- /dev/null
+++ b/tests/ui/consts/const-unstable-intrinsic.rs
@@ -0,0 +1,76 @@
+//! Ensure that unstable intrinsics can actually not be called,
+//! neither within a crate nor cross-crate.
+//@ aux-build:unstable_intrinsic.rs
+#![feature(staged_api, rustc_attrs, intrinsics)]
+#![stable(since="1.0.0", feature = "stable")]
+#![feature(local)]
+
+extern crate unstable_intrinsic;
+
+fn main() {
+    const_main();
+}
+
+const fn const_main() {
+    let x = 42;
+    unsafe {
+        unstable_intrinsic::old_way::size_of_val(&x);
+        //~^ERROR: unstable library feature 'unstable'
+        //~|ERROR: cannot call non-const intrinsic
+        unstable_intrinsic::old_way::min_align_of_val(&x);
+        //~^ERROR: unstable library feature 'unstable'
+        //~|ERROR: not yet stable as a const intrinsic
+        unstable_intrinsic::new_way::size_of_val(&x);
+        //~^ERROR: unstable library feature 'unstable'
+        //~|ERROR: cannot be (indirectly) exposed to stable
+        unstable_intrinsic::new_way::min_align_of_val(&x);
+        //~^ERROR: unstable library feature 'unstable'
+        //~|ERROR: not yet stable as a const intrinsic
+
+        old_way::size_of_val(&x);
+        //~^ERROR: cannot call non-const intrinsic
+        old_way::min_align_of_val(&x);
+        //~^ERROR: cannot use `#[feature(local)]`
+        new_way::size_of_val(&x);
+        //~^ERROR: cannot be (indirectly) exposed to stable
+        new_way::min_align_of_val(&x);
+        //~^ERROR: cannot use `#[feature(local)]`
+    }
+}
+
+#[stable(since="1.0.0", feature = "stable")]
+pub mod old_way {
+    extern "rust-intrinsic" {
+        #[unstable(feature = "local", issue = "42")]
+        pub fn size_of_val<T>(x: *const T) -> usize;
+
+        #[unstable(feature = "local", issue = "42")]
+        #[rustc_const_unstable(feature = "local", issue = "42")]
+        pub fn min_align_of_val<T>(x: *const T) -> usize;
+    }
+}
+
+#[stable(since="1.0.0", feature = "stable")]
+pub mod new_way {
+    #[unstable(feature = "local", issue = "42")]
+    #[rustc_intrinsic]
+    pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
+
+    #[unstable(feature = "local", issue = "42")]
+    #[rustc_const_unstable(feature = "local", issue = "42")]
+    #[rustc_intrinsic]
+    pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+#[inline]
+pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
+    // Const stability attributes are not inherited from parent items.
+    extern "rust-intrinsic" {
+        fn copy<T>(src: *const T, dst: *mut T, count: usize);
+    }
+
+    unsafe { copy(src, dst, count) }
+    //~^ ERROR cannot call non-const intrinsic
+}
diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr
new file mode 100644
index 00000000000..33a434c503d
--- /dev/null
+++ b/tests/ui/consts/const-unstable-intrinsic.stderr
@@ -0,0 +1,127 @@
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/const-unstable-intrinsic.rs:17:9
+   |
+LL |         unstable_intrinsic::old_way::size_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/const-unstable-intrinsic.rs:20:9
+   |
+LL |         unstable_intrinsic::old_way::min_align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/const-unstable-intrinsic.rs:23:9
+   |
+LL |         unstable_intrinsic::new_way::size_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/const-unstable-intrinsic.rs:26:9
+   |
+LL |         unstable_intrinsic::new_way::min_align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: cannot call non-const intrinsic `size_of_val` in constant functions
+  --> $DIR/const-unstable-intrinsic.rs:17:9
+   |
+LL |         unstable_intrinsic::old_way::size_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `min_align_of_val` is not yet stable as a const intrinsic
+  --> $DIR/const-unstable-intrinsic.rs:20:9
+   |
+LL |         unstable_intrinsic::old_way::min_align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+
+error: intrinsic `unstable_intrinsic::new_way::size_of_val` cannot be (indirectly) exposed to stable
+  --> $DIR/const-unstable-intrinsic.rs:23:9
+   |
+LL |         unstable_intrinsic::new_way::size_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval)
+
+error: `min_align_of_val` is not yet stable as a const intrinsic
+  --> $DIR/const-unstable-intrinsic.rs:26:9
+   |
+LL |         unstable_intrinsic::new_way::min_align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+
+error: cannot call non-const intrinsic `size_of_val` in constant functions
+  --> $DIR/const-unstable-intrinsic.rs:30:9
+   |
+LL |         old_way::size_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
+  --> $DIR/const-unstable-intrinsic.rs:32:9
+   |
+LL |         old_way::min_align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+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 | const fn const_main() {
+   |
+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)]
+LL | const fn const_main() {
+   |
+
+error: intrinsic `new_way::size_of_val` cannot be (indirectly) exposed to stable
+  --> $DIR/const-unstable-intrinsic.rs:34:9
+   |
+LL |         new_way::size_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval)
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
+  --> $DIR/const-unstable-intrinsic.rs:36:9
+   |
+LL |         new_way::min_align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+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 | const fn const_main() {
+   |
+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)]
+LL | const fn const_main() {
+   |
+
+error: cannot call non-const intrinsic `copy` in constant functions
+  --> $DIR/const-unstable-intrinsic.rs:74:14
+   |
+LL |     unsafe { copy(src, dst, count) }
+   |              ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs
index 805c03da546..62917c0b98b 100644
--- a/tests/ui/consts/copy-intrinsic.rs
+++ b/tests/ui/consts/copy-intrinsic.rs
@@ -5,9 +5,11 @@
 use std::mem;
 
 extern "rust-intrinsic" {
+    #[stable(feature = "dummy", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
     fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
 
+    #[stable(feature = "dummy", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
     fn copy<T>(src: *const T, dst: *mut T, count: usize);
 }
diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr
index da8139129c9..29a88f6270b 100644
--- a/tests/ui/consts/copy-intrinsic.stderr
+++ b/tests/ui/consts/copy-intrinsic.stderr
@@ -1,23 +1,23 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:28:5
+  --> $DIR/copy-intrinsic.rs:30:5
    |
 LL |     copy_nonoverlapping(0x100 as *const i32, dangle, 1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x100[noalloc] which is a dangling pointer (it has no provenance)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:37:5
+  --> $DIR/copy-intrinsic.rs:39:5
    |
 LL |     copy_nonoverlapping(dangle, 0x100 as *mut i32, 1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:44:5
+  --> $DIR/copy-intrinsic.rs:46:5
    |
 LL |     copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy`
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:50:5
+  --> $DIR/copy-intrinsic.rs:52:5
    |
 LL |     copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping`
diff --git a/tests/ui/consts/intrinsic_without_const_stab.rs b/tests/ui/consts/intrinsic_without_const_stab.rs
deleted file mode 100644
index 40ec65d51be..00000000000
--- a/tests/ui/consts/intrinsic_without_const_stab.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-#![feature(intrinsics, staged_api)]
-#![stable(feature = "core", since = "1.6.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
-#[inline]
-pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
-    // Const stability attributes are not inherited from parent items.
-    extern "rust-intrinsic" {
-        fn copy<T>(src: *const T, dst: *mut T, count: usize);
-    }
-
-    unsafe { copy(src, dst, count) }
-    //~^ ERROR cannot call non-const fn
-}
-
-fn main() {}
diff --git a/tests/ui/consts/intrinsic_without_const_stab.stderr b/tests/ui/consts/intrinsic_without_const_stab.stderr
deleted file mode 100644
index e3143080c5f..00000000000
--- a/tests/ui/consts/intrinsic_without_const_stab.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0015]: cannot call non-const fn `copy::copy::<T>` in constant functions
-  --> $DIR/intrinsic_without_const_stab.rs:13:14
-   |
-LL |     unsafe { copy(src, dst, count) }
-   |              ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/intrinsic_without_const_stab_fail.rs b/tests/ui/consts/intrinsic_without_const_stab_fail.rs
deleted file mode 100644
index 2b0745b3c11..00000000000
--- a/tests/ui/consts/intrinsic_without_const_stab_fail.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(intrinsics, staged_api)]
-#![stable(feature = "core", since = "1.6.0")]
-
-extern "rust-intrinsic" {
-    fn copy<T>(src: *const T, dst: *mut T, count: usize);
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
-#[inline]
-pub const unsafe fn stuff<T>(src: *const T, dst: *mut T, count: usize) {
-    unsafe { copy(src, dst, count) } //~ ERROR cannot call non-const fn
-}
-
-fn main() {}
diff --git a/tests/ui/consts/intrinsic_without_const_stab_fail.stderr b/tests/ui/consts/intrinsic_without_const_stab_fail.stderr
deleted file mode 100644
index 8ade68eb2a9..00000000000
--- a/tests/ui/consts/intrinsic_without_const_stab_fail.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0015]: cannot call non-const fn `copy::<T>` in constant functions
-  --> $DIR/intrinsic_without_const_stab_fail.rs:12:14
-   |
-LL |     unsafe { copy(src, dst, count) }
-   |              ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
index 461499e942f..d6f07994e82 100644
--- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
+++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
@@ -5,7 +5,7 @@
             issue = "none")]
 
 #![feature(foo, foo2)]
-#![feature(const_async_blocks, staged_api)]
+#![feature(const_async_blocks, staged_api, rustc_attrs)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature="foo", issue = "none")]
@@ -14,33 +14,55 @@ const fn foo() -> u32 { 42 }
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn
+const fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]`
 
 #[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature = "foo2", issue = "none")]
 const fn foo2() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn
+const fn bar2() -> u32 { foo2() } //~ ERROR cannot use `#[feature(foo2)]`
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // conformity is required
 const fn bar3() -> u32 {
     let x = async { 13 };
-    //~^ ERROR const-stable function cannot use `#[feature(const_async_blocks)]`
+    //~^ ERROR cannot use `#[feature(const_async_blocks)]`
     foo()
-    //~^ ERROR is not yet stable as a const fn
+    //~^ ERROR cannot use `#[feature(foo)]`
 }
 
 // check whether this function cannot be called even with the feature gate active
 #[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature = "foo2", issue = "none")]
 const fn foo2_gated() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn
+const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
+
+// Functions without any attribute are checked like stable functions,
+// even if they are in a stable module.
+mod stable {
+    #![stable(feature = "rust1", since = "1.0.0")]
+
+    pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
+}
+// And same for const-unstable functions that are marked as "stable_indirect".
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo", issue = "none")]
+#[rustc_const_stable_indirect]
+const fn stable_indirect() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
+
+// These functiuons *can* be called from fully stable functions.
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
+const fn bar2_gated_exposed() -> u32 {
+    stable::bar2_gated_stable_indirect() + stable_indirect()
+}
 
 fn main() {}
diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
index fedc5a4809d..899cec07ac7 100644
--- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
+++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
@@ -1,51 +1,127 @@
-error: `foo` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
   --> $DIR/min_const_fn_libstd_stability.rs:17:25
    |
 LL | const fn bar() -> u32 { foo() }
    |                         ^^^^^
    |
-   = 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 bar() -> u32 { foo() }
+   |
+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(foo)]
+LL | const fn bar() -> u32 { foo() }
+   |
 
-error: `foo2` is not yet stable as a const fn
-  --> $DIR/min_const_fn_libstd_stability.rs:25:26
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_fn_libstd_stability.rs:26:26
    |
 LL | const fn bar2() -> u32 { foo2() }
    |                          ^^^^^^
    |
-   = 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 bar2() -> u32 { foo2() }
+   |
+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(foo2)]
+LL | const fn bar2() -> u32 { foo2() }
+   |
 
-error: const-stable function cannot use `#[feature(const_async_blocks)]`
-  --> $DIR/min_const_fn_libstd_stability.rs:31:13
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_async_blocks)]`
+  --> $DIR/min_const_fn_libstd_stability.rs:32:13
    |
 LL |     let x = async { 13 };
    |             ^^^^^^^^^^^^
    |
-help: if the function is not (yet) meant to be stable, make this function unstably const
+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 | const fn bar3() -> u32 {
    |
-help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval)
+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 | const fn bar3() -> u32 {
    |
 
-error: `foo` is not yet stable as a const fn
-  --> $DIR/min_const_fn_libstd_stability.rs:33:5
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
+  --> $DIR/min_const_fn_libstd_stability.rs:34:5
    |
 LL |     foo()
    |     ^^^^^
    |
-   = 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 bar3() -> u32 {
+   |
+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(foo)]
+LL | const fn bar3() -> u32 {
+   |
 
-error: `foo2_gated` is not yet stable as a const fn
-  --> $DIR/min_const_fn_libstd_stability.rs:44:32
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_fn_libstd_stability.rs:46:32
    |
 LL | const fn bar2_gated() -> u32 { foo2_gated() }
    |                                ^^^^^^^^^^^^
    |
-   = 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 bar2_gated() -> u32 { foo2_gated() }
+   |
+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(foo2)]
+LL | const fn bar2_gated() -> u32 { foo2_gated() }
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_fn_libstd_stability.rs:53:63
+   |
+LL |     pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() }
+   |                                                               ^^^^^^^^^^^^^^^^^^^
+   |
+   = 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(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() }
+   |
+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(foo2)]
+LL |     pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() }
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_fn_libstd_stability.rs:59:37
+   |
+LL | const fn stable_indirect() -> u32 { foo2_gated() }
+   |                                     ^^^^^^^^^^^^
+   |
+   = 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_indirect() -> u32 { foo2_gated() }
+   |
+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(foo2)]
+LL | const fn stable_indirect() -> u32 { foo2_gated() }
+   |
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
index 274b4444799..3e82b9ff924 100644
--- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
+++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
@@ -13,24 +13,26 @@ const unsafe fn foo() -> u32 { 42 }
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR not yet stable as a const fn
+const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR cannot use `#[feature(foo)]`
 
 #[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature = "foo2", issue = "none")]
 const unsafe fn foo2() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as a const fn
+const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR cannot use `#[feature(foo2)]`
 
 // check whether this function cannot be called even with the feature gate active
 #[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature = "foo2", issue = "none")]
 const unsafe fn foo2_gated() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
-//~^ ERROR not yet stable as a const fn
+//~^ ERROR cannot use `#[feature(foo2)]`
 
 fn main() {}
diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
index 353b117efbc..442a079020f 100644
--- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
+++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
@@ -1,26 +1,56 @@
-error: `foo` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
   --> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41
    |
 LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
    |                                         ^^^^^
    |
-   = 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 unsafe fn bar() -> u32 { unsafe { foo() } }
+   |
+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(foo)]
+LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
+   |
 
-error: `foo2` is not yet stable as a const fn
-  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:25:42
    |
 LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
    |                                          ^^^^^^
    |
-   = 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 unsafe fn bar2() -> u32 { unsafe { foo2() } }
+   |
+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(foo2)]
+LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
+   |
 
-error: `foo2_gated` is not yet stable as a const fn
-  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:33:48
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:35:48
    |
 LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
    |                                                ^^^^^^^^^^^^
    |
-   = 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 unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
+   |
+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(foo2)]
+LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
index 94b62071362..cc7eaa51a6f 100644
--- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
+++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
@@ -13,23 +13,25 @@ const fn foo() -> u32 { 42 }
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn
+const unsafe fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]`
 
 #[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature="foo2", issue = "none")]
 const fn foo2() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn
+const unsafe fn bar2() -> u32 { foo2() } //~ ERROR cannot use `#[feature(foo2)]`
 
 // check whether this function cannot be called even with the feature gate active
 #[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature="foo2", issue = "none")]
 const fn foo2_gated() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn
+const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
 
 fn main() {}
diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
index e90ba9b912f..ff37cba7b9a 100644
--- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
+++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
@@ -1,26 +1,56 @@
-error: `foo` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
   --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32
    |
 LL | const unsafe fn bar() -> u32 { foo() }
    |                                ^^^^^
    |
-   = 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 unsafe fn bar() -> u32 { foo() }
+   |
+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(foo)]
+LL | const unsafe fn bar() -> u32 { foo() }
+   |
 
-error: `foo2` is not yet stable as a const fn
-  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:25:33
    |
 LL | const unsafe fn bar2() -> u32 { foo2() }
    |                                 ^^^^^^
    |
-   = 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 unsafe fn bar2() -> u32 { foo2() }
+   |
+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(foo2)]
+LL | const unsafe fn bar2() -> u32 { foo2() }
+   |
 
-error: `foo2_gated` is not yet stable as a const fn
-  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:35:39
    |
 LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
    |                                       ^^^^^^^^^^^^
    |
-   = 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 unsafe fn bar2_gated() -> u32 { foo2_gated() }
+   |
+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(foo2)]
+LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/rustc-const-stability-require-const.rs b/tests/ui/consts/rustc-const-stability-require-const.rs
index 4fb259b335c..1c66f6e2aa5 100644
--- a/tests/ui/consts/rustc-const-stability-require-const.rs
+++ b/tests/ui/consts/rustc-const-stability-require-const.rs
@@ -1,16 +1,16 @@
 #![crate_type = "lib"]
-#![feature(staged_api)]
+#![feature(staged_api, rustc_attrs)]
 #![stable(feature = "foo", since = "1.0.0")]
 
 #[stable(feature = "foo", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_foo", issue = "none")]
 pub fn foo() {}
-//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+//~^ ERROR require the function or method to be `const`
 
 #[stable(feature = "bar", since = "1.0.0")]
 #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
 pub fn bar() {}
-//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+//~^ ERROR require the function or method to be `const`
 
 #[stable(feature = "potato", since = "1.0.0")]
 pub struct Potato;
@@ -19,23 +19,23 @@ impl Potato {
     #[stable(feature = "salad", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_salad", issue = "none")]
     pub fn salad(&self) -> &'static str { "mmmmmm" }
-    //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+    //~^ ERROR require the function or method to be `const`
 
     #[stable(feature = "roasted", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_roasted", issue = "none")]
     pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
-    //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+    //~^ ERROR require the function or method to be `const`
 }
 
 #[stable(feature = "bar", since = "1.0.0")]
 #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
 pub extern "C" fn bar_c() {}
-//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+//~^ ERROR require the function or method to be `const`
 
 #[stable(feature = "foo", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_foo", issue = "none")]
 pub extern "C" fn foo_c() {}
-//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+//~^ ERROR require the function or method to be `const`
 
 
 #[stable(feature = "foobar", since = "1.0.0")]
@@ -45,3 +45,21 @@ pub const fn foobar() {}
 #[stable(feature = "barfoo", since = "1.0.0")]
 #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
 pub const fn barfoo() {}
+
+// `rustc_const_stable` also requires the function to be stable.
+// FIXME: these are disabled until <https://github.com/rust-lang/stdarch/pull/1654> propagates.
+
+#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
+const fn barfoo_unmarked() {}
+// FIXME disabled ERROR can only be applied to functions that are declared `#[stable]`
+
+#[unstable(feature = "unstable", issue = "none")]
+#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
+pub const fn barfoo_unstable() {}
+// FIXME disabled ERROR can only be applied to functions that are declared `#[stable]`
+
+// `#[rustc_const_stable_indirect]` also requires a const fn
+#[rustc_const_stable_indirect]
+#[unstable(feature = "unstable", issue = "none")]
+pub fn not_a_const_fn() {}
+//~^ ERROR require the function or method to be `const`
diff --git a/tests/ui/consts/rustc-const-stability-require-const.stderr b/tests/ui/consts/rustc-const-stability-require-const.stderr
index 1027b9311b7..09b96ce6f83 100644
--- a/tests/ui/consts/rustc-const-stability-require-const.stderr
+++ b/tests/ui/consts/rustc-const-stability-require-const.stderr
@@ -1,8 +1,6 @@
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
   --> $DIR/rustc-const-stability-require-const.rs:7:1
    |
-LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")]
-   | -------------------------------------------------------------- attribute specified here
 LL | pub fn foo() {}
    | ^^^^^^^^^^^^
    |
@@ -12,11 +10,9 @@ help: make the function or method const
 LL | pub fn foo() {}
    | ^^^^^^^^^^^^
 
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
   --> $DIR/rustc-const-stability-require-const.rs:12:1
    |
-LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
-   | ------------------------------------------------------------- attribute specified here
 LL | pub fn bar() {}
    | ^^^^^^^^^^^^
    |
@@ -26,11 +22,9 @@ help: make the function or method const
 LL | pub fn bar() {}
    | ^^^^^^^^^^^^
 
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
   --> $DIR/rustc-const-stability-require-const.rs:21:5
    |
-LL |     #[rustc_const_unstable(feature = "const_salad", issue = "none")]
-   |     ---------------------------------------------------------------- attribute specified here
 LL |     pub fn salad(&self) -> &'static str { "mmmmmm" }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -40,11 +34,9 @@ help: make the function or method const
 LL |     pub fn salad(&self) -> &'static str { "mmmmmm" }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
   --> $DIR/rustc-const-stability-require-const.rs:26:5
    |
-LL |     #[rustc_const_unstable(feature = "const_roasted", issue = "none")]
-   |     ------------------------------------------------------------------ attribute specified here
 LL |     pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -54,11 +46,9 @@ help: make the function or method const
 LL |     pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
   --> $DIR/rustc-const-stability-require-const.rs:32:1
    |
-LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
-   | ------------------------------------------------------------- attribute specified here
 LL | pub extern "C" fn bar_c() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -68,11 +58,9 @@ help: make the function or method const
 LL | pub extern "C" fn bar_c() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
   --> $DIR/rustc-const-stability-require-const.rs:37:1
    |
-LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")]
-   | -------------------------------------------------------------- attribute specified here
 LL | pub extern "C" fn foo_c() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -82,5 +70,17 @@ help: make the function or method const
 LL | pub extern "C" fn foo_c() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
+  --> $DIR/rustc-const-stability-require-const.rs:64:1
+   |
+LL | pub fn not_a_const_fn() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function or method const
+  --> $DIR/rustc-const-stability-require-const.rs:64:1
+   |
+LL | pub fn not_a_const_fn() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/consts/unstable-const-stable.rs b/tests/ui/consts/unstable-const-stable.rs
deleted file mode 100644
index f69e8d0efe5..00000000000
--- a/tests/ui/consts/unstable-const-stable.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//@ aux-build:unstable_but_const_stable.rs
-
-extern crate unstable_but_const_stable;
-use unstable_but_const_stable::*;
-
-fn main() {
-    some_unstable_fn(); //~ERROR use of unstable library feature
-    unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature
-}
-
-const fn const_main() {
-    some_unstable_fn(); //~ERROR use of unstable library feature
-    unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature
-}
diff --git a/tests/ui/consts/unstable-const-stable.stderr b/tests/ui/consts/unstable-const-stable.stderr
deleted file mode 100644
index c4ffbbb60db..00000000000
--- a/tests/ui/consts/unstable-const-stable.stderr
+++ /dev/null
@@ -1,43 +0,0 @@
-error[E0658]: use of unstable library feature 'unstable'
-  --> $DIR/unstable-const-stable.rs:7:5
-   |
-LL |     some_unstable_fn();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature 'unstable'
-  --> $DIR/unstable-const-stable.rs:8:14
-   |
-LL |     unsafe { write_bytes(4 as *mut u8, 0, 0) };
-   |              ^^^^^^^^^^^
-   |
-   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature 'unstable'
-  --> $DIR/unstable-const-stable.rs:12:5
-   |
-LL |     some_unstable_fn();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature 'unstable'
-  --> $DIR/unstable-const-stable.rs:13:14
-   |
-LL |     unsafe { write_bytes(4 as *mut u8, 0, 0) };
-   |              ^^^^^^^^^^^
-   |
-   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr
index 319056a9c88..d599523c727 100644
--- a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr
+++ b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr
@@ -1,31 +1,31 @@
 error: can't mark as unstable using an already stable feature
-  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1
+  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
    |
-LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
 LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
 LL | const fn my_fun() {}
    | -------------------- the stability attribute annotates this item
    |
 help: consider removing the attribute
-  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1
+  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
    |
-LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: can't mark as unstable using an already stable feature
-  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
+  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1
    |
+LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
 LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
 LL | const fn my_fun() {}
    | -------------------- the stability attribute annotates this item
    |
 help: consider removing the attribute
-  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
+  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1
    |
-LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/intrinsics/const-eval-select-stability.rs b/tests/ui/intrinsics/const-eval-select-stability.rs
index 575bc0cadda..25cbadaa22d 100644
--- a/tests/ui/intrinsics/const-eval-select-stability.rs
+++ b/tests/ui/intrinsics/const-eval-select-stability.rs
@@ -15,7 +15,7 @@ const fn nothing(){}
 #[rustc_const_stable(since = "1.0", feature = "const_hey")]
 pub const fn hey() {
     const_eval_select((), nothing, log);
-    //~^ ERROR `const_eval_select` is not yet stable as a const fn
+    //~^ ERROR cannot use `#[feature(const_eval_select)]`
 }
 
 fn main() {}
diff --git a/tests/ui/intrinsics/const-eval-select-stability.stderr b/tests/ui/intrinsics/const-eval-select-stability.stderr
index 335b9877aa0..5f443b1d4ff 100644
--- a/tests/ui/intrinsics/const-eval-select-stability.stderr
+++ b/tests/ui/intrinsics/const-eval-select-stability.stderr
@@ -1,10 +1,19 @@
-error: `const_eval_select` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_eval_select)]`
   --> $DIR/const-eval-select-stability.rs:17:5
    |
 LL |     const_eval_select((), nothing, log);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+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 hey() {
+   |
+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_eval_select)]
+LL | pub const fn hey() {
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs
index 4089ec72885..6d6d793c62b 100644
--- a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs
@@ -14,4 +14,3 @@ pub const fn foobar() -> u32 {
 }
 
 const VAR: u32 = foobar();
-//~^ ERROR: `foobar` is not yet stable as a const fn
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr
index 918d6ebf992..232de41c769 100644
--- a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr
@@ -4,13 +4,5 @@ error: feature `const_bar` implying `const_foobar` does not exist
 LL | #[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `foobar` is not yet stable as a const fn
-  --> $DIR/const-stability-attribute-implies-missing.rs:16:18
-   |
-LL | const VAR: u32 = foobar();
-   |                  ^^^^^^^^
-   |
-   = help: add `#![feature(const_foobar)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/stability-attribute/missing-const-stability.rs b/tests/ui/stability-attribute/missing-const-stability.rs
index 82da18cc9ac..f1139652550 100644
--- a/tests/ui/stability-attribute/missing-const-stability.rs
+++ b/tests/ui/stability-attribute/missing-const-stability.rs
@@ -1,6 +1,6 @@
 //@ compile-flags: -Znext-solver
 #![feature(staged_api)]
-#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
+#![feature(const_trait_impl, effects, rustc_attrs, intrinsics)] //~ WARN the feature `effects` is incomplete
 #![stable(feature = "stable", since = "1.0.0")]
 
 #[stable(feature = "stable", since = "1.0.0")]
@@ -31,4 +31,15 @@ impl const Bar for Foo {
     fn fun() {}
 }
 
+#[stable(feature = "stable", since = "1.0.0")]
+#[rustc_intrinsic]
+pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
+//~^ ERROR function has missing const stability attribute
+
+extern "rust-intrinsic" {
+    #[stable(feature = "stable", since = "1.0.0")]
+    #[rustc_const_stable_indirect]
+    pub fn min_align_of_val<T>(x: *const T) -> usize;
+}
+
 fn main() {}
diff --git a/tests/ui/stability-attribute/missing-const-stability.stderr b/tests/ui/stability-attribute/missing-const-stability.stderr
index adf60c38611..e62a8b88261 100644
--- a/tests/ui/stability-attribute/missing-const-stability.stderr
+++ b/tests/ui/stability-attribute/missing-const-stability.stderr
@@ -1,7 +1,7 @@
 warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/missing-const-stability.rs:3:30
    |
-LL | #![feature(const_trait_impl, effects)]
+LL | #![feature(const_trait_impl, effects, rustc_attrs, intrinsics)]
    |                              ^^^^^^^
    |
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
@@ -22,11 +22,17 @@ LL | |     fn fun() {}
 LL | | }
    | |_^
 
+error: function has missing const stability attribute
+  --> $DIR/missing-const-stability.rs:36:1
+   |
+LL | pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: associated function has missing const stability attribute
   --> $DIR/missing-const-stability.rs:16:5
    |
 LL |     pub const fn foo() {}
    |     ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 4 previous errors; 1 warning emitted
 
diff --git a/tests/ui/target-feature/feature-hierarchy.rs b/tests/ui/target-feature/feature-hierarchy.rs
index 4cf9112810c..7f14d700ecb 100644
--- a/tests/ui/target-feature/feature-hierarchy.rs
+++ b/tests/ui/target-feature/feature-hierarchy.rs
@@ -19,6 +19,7 @@ trait Copy {}
 impl Copy for bool {}
 
 extern "rust-intrinsic" {
+    #[stable(feature = "test", since = "1.0.0")]
     #[rustc_const_stable(feature = "test", since = "1.0.0")]
     fn unreachable() -> !;
 }
diff --git a/tests/ui/target-feature/no-llvm-leaks.rs b/tests/ui/target-feature/no-llvm-leaks.rs
index 9f5dec4447f..f0c887bc1e0 100644
--- a/tests/ui/target-feature/no-llvm-leaks.rs
+++ b/tests/ui/target-feature/no-llvm-leaks.rs
@@ -17,6 +17,7 @@ trait Copy {}
 impl Copy for bool {}
 
 extern "rust-intrinsic" {
+    #[stable(feature = "test", since = "1.0.0")]
     #[rustc_const_stable(feature = "test", since = "1.0.0")]
     fn unreachable() -> !;
 }
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