From d834ea03dcb624a6ea8780a3676647df816edc06 Mon Sep 17 00:00:00 2001
From: ltdk <usr@ltdk.xyz>
Date: Sat, 4 Nov 2023 04:10:23 -0400
Subject: [PATCH] Say what unstable feature is being used in a const-stable
 function

---
 .../src/transform/check_consts/check.rs       | 10 ++--
 .../src/transform/check_consts/ops.rs         | 10 +++-
 .../min_const_fn_libstd_stability.rs          |  6 +--
 .../min_const_fn_libstd_stability.stderr      | 13 +++++-
 .../min_const_unsafe_fn_libstd_stability.rs   |  6 +--
 ...in_const_unsafe_fn_libstd_stability.stderr | 13 +++++-
 .../min_const_unsafe_fn_libstd_stability2.rs  |  6 +--
 ...n_const_unsafe_fn_libstd_stability2.stderr | 13 +++++-
 .../intrinsics/const-eval-select-stability.rs |  2 +-
 .../const-eval-select-stability.stderr        | 13 +++++-
 .../rfc-2632-const-trait-impl/staged-api.rs   |  6 +--
 .../staged-api.unstable.stderr                | 46 +++++++++++++++----
 12 files changed, 108 insertions(+), 36 deletions(-)

diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index effaedd0820c3..4019ea817533e 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -295,17 +295,19 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
         let gate = match op.status_in_item(self.ccx) {
             Status::Allowed => return,
 
-            Status::Unstable(gate) if self.tcx.features().active(gate) => {
+            Status::Unstable(gate) => {
                 let unstable_in_stable = self.ccx.is_const_stable_const_fn()
                     && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate);
                 if unstable_in_stable {
                     emit_unstable_in_stable_error(self.ccx, span, gate);
+                    return;
+                } else if self.tcx.features().declared(gate) && self.tcx.features().active(gate) {
+                    return;
+                } else {
+                    Some(gate)
                 }
-
-                return;
             }
 
-            Status::Unstable(gate) => Some(gate),
             Status::Forbidden => None,
         };
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 5b4bbf8510b60..fe49bb935c28b 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -317,6 +317,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
 pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
 
 impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
+    fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
+        if let Some(symbol) = self.1 { Status::Unstable(symbol) } else { Status::Forbidden }
+    }
+
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let FnCallUnstable(def_id, feature) = *self;
 
@@ -327,7 +331,11 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
         // FIXME: make this translatable
         #[allow(rustc::untranslatable_diagnostic)]
         if ccx.is_const_stable_const_fn() {
-            err.help("const-stable functions can only call other const-stable functions");
+            if self.1.is_some() {
+                bug!("this should be triggering the UnstableInStable lint instead");
+            } else {
+                err.help("const-stable functions can only call other const-stable functions");
+            }
         } else if ccx.tcx.sess.is_nightly_build() {
             if let Some(feature) = feature {
                 err.help(format!("add `#![feature({feature})]` to the crate attributes to enable"));
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 bb240fb4ad62c..2adf14e38f9aa 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
@@ -13,7 +13,7 @@ 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 const-stable function cannot use `#[feature(foo)]`
 
 #[unstable(feature = "foo2", issue = "none")]
 const fn foo2() -> u32 { 42 }
@@ -21,7 +21,7 @@ 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 const-stable function cannot use `#[feature(foo2)]`
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
@@ -36,6 +36,6 @@ 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 const-stable function cannot use `#[feature(foo2)]`
 
 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 7ec2508ca93a6..b1e80eccb2c7b 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,10 +1,19 @@
-error: `foo` is not yet stable as a const fn
+error: const-stable function cannot use `#[feature(foo)]`
   --> $DIR/min_const_fn_libstd_stability.rs:16:25
    |
 LL | const fn bar() -> u32 { foo() }
    |                         ^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+help: if it is not part of the public API, make this function unstably const
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn bar() -> u32 { foo() }
+   |
+help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
+   |
+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:24:26
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 03084c8674dc2..234a9342a5716 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,7 +13,7 @@ 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 const-stable function cannot use `#[feature(foo)]`
 
 #[unstable(feature = "foo2", issue = "none")]
 const unsafe fn foo2() -> u32 { 42 }
@@ -21,7 +21,7 @@ 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 const-stable function cannot use `#[feature(foo2)]`
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
@@ -37,6 +37,6 @@ const unsafe fn foo2_gated() -> u32 { 42 }
 #[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 const-stable function 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 72c1f175d1d6b..701d91f5fedd9 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,10 +1,19 @@
-error: `foo` is not yet stable as a const fn
+error: const-stable function 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: if it is not part of the public API, make this function unstably const
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
+   |
+help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
+   |
+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
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 94b6207136298..2e36c52ce2e82 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,7 +13,7 @@ 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 const-stable function cannot use `#[feature(foo)]`
 
 #[unstable(feature = "foo2", issue = "none")]
 const fn foo2() -> u32 { 42 }
@@ -21,7 +21,7 @@ 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 const-stable function cannot use `#[feature(foo)]`
 
 // check whether this function cannot be called even with the feature gate active
 #[unstable(feature = "foo2", issue = "none")]
@@ -30,6 +30,6 @@ 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 const-stable function cannot use `#[feature(foo)]`
 
 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 e90ba9b912fe1..f6230f8a5ae82 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,10 +1,19 @@
-error: `foo` is not yet stable as a const fn
+error: const-stable function 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: if it is not part of the public API, make this function unstably const
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar() -> u32 { foo() }
+   |
+help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
+   |
+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
diff --git a/tests/ui/intrinsics/const-eval-select-stability.rs b/tests/ui/intrinsics/const-eval-select-stability.rs
index f9554decec16b..3bb161aef8957 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 unsafe fn hey() {
     const_eval_select((), nothing, log);
-    //~^ ERROR `const_eval_select` is not yet stable as a const fn
+    //~^ ERROR const-stable function 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 335b9877aa008..6ccee6a6262b9 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-stable function 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 it is not part of the public API, make this function unstably const
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | pub const unsafe fn hey() {
+   |
+help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
+   |
+LL + #[rustc_allow_const_fn_unstable(const_eval_select)]
+LL | pub const unsafe fn hey() {
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs
index 31ca9419589cb..4e99d5f48d942 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs
@@ -51,11 +51,11 @@ pub const fn const_context_not_const_stable() {
 #[rustc_const_stable(feature = "cheese", since = "1.0.0")]
 const fn stable_const_context() {
     Unstable::func();
-    //~^ ERROR not yet stable as a const fn
+    //~^ ERROR const-stable function cannot use `#[feature(unstable)]`
     Foo::func();
-    //[unstable]~^ ERROR not yet stable as a const fn
+    //[unstable]~^ ERROR const-stable function cannot use `#[feature(foo)]`
     const_context_not_const_stable()
-    //[unstable]~^ ERROR not yet stable as a const fn
+    //[unstable]~^ ERROR const-stable function cannot use `#[feature(foo)]`
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr
index c9ca15d5b565f..4bc028554481b 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr
@@ -14,29 +14,55 @@ LL |     Foo::func();
    |
    = help: add `#![feature(foo)]` 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:53:5
+error: const-stable function cannot use `#[feature(unstable)]`
+  --> $DIR/staged-api.rs:55:5
    |
 LL |     Unstable::func();
    |     ^^^^^^^^^^^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+help: if it is not part of the public API, make this function unstably const
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_const_context() {
+   |
+help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
+   |
+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:55:5
+error: const-stable function cannot use `#[feature(foo)]`
+  --> $DIR/staged-api.rs:57:5
    |
 LL |     Foo::func();
    |     ^^^^^^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+help: if it is not part of the public API, make this function unstably const
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_const_context() {
+   |
+help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
+   |
+LL + #[rustc_allow_const_fn_unstable(foo)]
+LL | const fn stable_const_context() {
+   |
 
-error: `const_context_not_const_stable` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:57:5
+error: const-stable function cannot use `#[feature(foo)]`
+  --> $DIR/staged-api.rs:59:5
    |
 LL |     const_context_not_const_stable()
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+help: if it is not part of the public API, make this function unstably const
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_const_context() {
+   |
+help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
+   |
+LL + #[rustc_allow_const_fn_unstable(foo)]
+LL | const fn stable_const_context() {
+   |
 
 error: aborting due to 5 previous errors
-