about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_const_eval/messages.ftl4
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs89
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs39
-rw-r--r--compiler/rustc_const_eval/src/errors.rs10
-rw-r--r--tests/ui/traits/const-traits/cross-crate.rs4
-rw-r--r--tests/ui/traits/const-traits/cross-crate.stock.stderr28
-rw-r--r--tests/ui/traits/const-traits/cross-crate.stocknc.stderr53
-rw-r--r--tests/ui/traits/const-traits/staged-api-user-crate.rs3
-rw-r--r--tests/ui/traits/const-traits/staged-api-user-crate.stderr24
-rw-r--r--tests/ui/traits/const-traits/staged-api.rs50
-rw-r--r--tests/ui/traits/const-traits/staged-api.stable.stderr89
-rw-r--r--tests/ui/traits/const-traits/staged-api.stderr139
-rw-r--r--tests/ui/traits/const-traits/staged-api.unstable.stderr108
13 files changed, 250 insertions, 390 deletions
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 826e34930ea..15027ae0c18 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -25,6 +25,10 @@ const_eval_closure_fndef_not_const =
     function defined here, but it is not `const`
 const_eval_closure_non_const =
     cannot call non-const closure in {const_eval_const_context}s
+
+const_eval_conditionally_const_call =
+    cannot call conditionally-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s
+
 const_eval_consider_dereferencing =
     consider dereferencing here
 
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index aea3d5bd3e7..8cd0ecb3e4e 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -15,7 +15,7 @@ use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 use rustc_mir_dataflow::Analysis;
 use rustc_mir_dataflow::impls::MaybeStorageLive;
 use rustc_mir_dataflow::storage::always_storage_live_locals;
@@ -361,31 +361,21 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
         !is_transient
     }
 
+    /// Returns whether there are const-conditions.
     fn revalidate_conditional_constness(
         &mut self,
         callee: DefId,
         callee_args: ty::GenericArgsRef<'tcx>,
-        call_source: CallSource,
         call_span: Span,
-    ) {
+    ) -> bool {
         let tcx = self.tcx;
         if !tcx.is_conditionally_const(callee) {
-            return;
+            return false;
         }
 
         let const_conditions = tcx.const_conditions(callee).instantiate(tcx, callee_args);
-        // If there are any const conditions on this fn and `const_trait_impl`
-        // is not enabled, simply bail. We shouldn't be able to call conditionally
-        // const functions on stable.
-        if !const_conditions.is_empty() && !tcx.features().const_trait_impl() {
-            self.check_op(ops::FnCallNonConst {
-                callee,
-                args: callee_args,
-                span: call_span,
-                call_source,
-                feature: Some(sym::const_trait_impl),
-            });
-            return;
+        if const_conditions.is_empty() {
+            return false;
         }
 
         let infcx = tcx.infer_ctxt().build(self.body.typing_mode(tcx));
@@ -421,6 +411,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
             tcx.dcx()
                 .span_delayed_bug(call_span, "this should have reported a ~const error in HIR");
         }
+
+        true
     }
 }
 
@@ -627,11 +619,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     _ => unreachable!(),
                 };
 
-                let ConstCx { tcx, body, param_env, .. } = *self.ccx;
+                let ConstCx { tcx, body, .. } = *self.ccx;
 
                 let fn_ty = func.ty(body, tcx);
 
-                let (mut callee, mut fn_args) = match *fn_ty.kind() {
+                let (callee, fn_args) = match *fn_ty.kind() {
                     ty::FnDef(def_id, fn_args) => (def_id, fn_args),
 
                     ty::FnPtr(..) => {
@@ -645,57 +637,38 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     }
                 };
 
-                self.revalidate_conditional_constness(callee, fn_args, call_source, *fn_span);
+                let has_const_conditions =
+                    self.revalidate_conditional_constness(callee, fn_args, *fn_span);
 
-                let mut is_trait = false;
                 // Attempting to call a trait method?
                 if let Some(trait_did) = tcx.trait_of_item(callee) {
-                    trace!("attempting to call a trait method");
+                    // We can't determine the actual callee here, so we have to do different checks
+                    // than usual.
 
+                    trace!("attempting to call a trait method");
                     let trait_is_const = tcx.is_const_trait(trait_did);
-                    // trait method calls are only permitted when `effects` is enabled.
-                    // typeck ensures the conditions for calling a const trait method are met,
-                    // so we only error if the trait isn't const. We try to resolve the trait
-                    // into the concrete method, and uses that for const stability checks.
-                    // FIXME(const_trait_impl) we might consider moving const stability checks
-                    // to typeck as well.
-                    if tcx.features().const_trait_impl() && trait_is_const {
-                        // This skips the check below that ensures we only call `const fn`.
-                        is_trait = true;
-
-                        if let Ok(Some(instance)) =
-                            Instance::try_resolve(tcx, param_env, callee, fn_args)
-                            && let InstanceKind::Item(def) = instance.def
-                        {
-                            // Resolve a trait method call to its concrete implementation, which may be in a
-                            // `const` trait impl. This is only used for the const stability check below, since
-                            // we want to look at the concrete impl's stability.
-                            fn_args = instance.args;
-                            callee = def;
-                        }
+
+                    if trait_is_const {
+                        // Trait calls are always conditionally-const.
+                        self.check_op(ops::ConditionallyConstCall { callee, args: fn_args });
+                        // FIXME(const_trait_impl): do a more fine-grained check whether this
+                        // particular trait can be const-stably called.
                     } else {
-                        // if the trait is const but the user has not enabled the feature(s),
-                        // suggest them.
-                        let feature = if trait_is_const {
-                            Some(if tcx.features().const_trait_impl() {
-                                sym::effects
-                            } else {
-                                sym::const_trait_impl
-                            })
-                        } else {
-                            None
-                        };
+                        // Not even a const trait.
                         self.check_op(ops::FnCallNonConst {
                             callee,
                             args: fn_args,
                             span: *fn_span,
                             call_source,
-                            feature,
                         });
-                        // If we allowed this, we're in miri-unleashed mode, so we might
-                        // as well skip the remaining checks.
-                        return;
                     }
+                    // That's all we can check here.
+                    return;
+                }
+
+                // Even if we know the callee, ensure we can use conditionally-const calls.
+                if has_const_conditions {
+                    self.check_op(ops::ConditionallyConstCall { callee, args: fn_args });
                 }
 
                 // At this point, we are calling a function, `callee`, whose `DefId` is known...
@@ -783,14 +756,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     return;
                 }
 
-                // Trait functions are not `const fn` so we have to skip them here.
-                if !tcx.is_const_fn(callee) && !is_trait {
+                if !tcx.is_const_fn(callee) {
                     self.check_op(ops::FnCallNonConst {
                         callee,
                         args: fn_args,
                         span: *fn_span,
                         call_source,
-                        feature: None,
                     });
                     // If we allowed this, we're in miri-unleashed mode, so we might
                     // as well skip the remaining checks.
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 2931159842f..5b745e6dffd 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -70,6 +70,34 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
     }
 }
 
+/// A call to a function that is in a trait, or has trait bounds that make it conditionally-const.
+#[derive(Debug)]
+pub(crate) struct ConditionallyConstCall<'tcx> {
+    pub callee: DefId,
+    pub args: GenericArgsRef<'tcx>,
+}
+
+impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> {
+    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
+        // We use the `const_trait_impl` gate for all conditionally-const calls.
+        Status::Unstable {
+            gate: sym::const_trait_impl,
+            safe_to_expose_on_stable: false,
+            // We don't want the "mark the callee as `#[rustc_const_stable_indirect]`" hint
+            is_function_call: false,
+        }
+    }
+
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
+        ccx.dcx().create_err(errors::ConditionallyConstCall {
+            span,
+            def_path_str: ccx.tcx.def_path_str_with_args(self.callee, self.args),
+            def_descr: ccx.tcx.def_descr(self.callee),
+            kind: ccx.const_kind(),
+        })
+    }
+}
+
 /// A function call where the callee is not marked as `const`.
 #[derive(Debug, Clone, Copy)]
 pub(crate) struct FnCallNonConst<'tcx> {
@@ -77,7 +105,6 @@ pub(crate) struct FnCallNonConst<'tcx> {
     pub args: GenericArgsRef<'tcx>,
     pub span: Span,
     pub call_source: CallSource,
-    pub feature: Option<Symbol>,
 }
 
 impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
@@ -85,7 +112,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
     #[allow(rustc::diagnostic_outside_of_impl)]
     #[allow(rustc::untranslatable_diagnostic)]
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
-        let FnCallNonConst { callee, args, span, call_source, feature } = *self;
+        let FnCallNonConst { callee, args, span, call_source } = *self;
         let ConstCx { tcx, param_env, .. } = *ccx;
         let caller = ccx.def_id();
 
@@ -285,14 +312,6 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
             ccx.const_kind(),
         ));
 
-        if let Some(feature) = feature {
-            ccx.tcx.disabled_nightly_features(
-                &mut err,
-                Some(ccx.tcx.local_def_id_to_hir_id(caller)),
-                [(String::new(), feature)],
-            );
-        }
-
         if let ConstContext::Static(_) = ccx.const_kind() {
             err.note(fluent_generated::const_eval_lazy_lock);
         }
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 14e8bebbb18..604e5ed61a3 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -177,6 +177,16 @@ pub(crate) struct NonConstFmtMacroCall {
 }
 
 #[derive(Diagnostic)]
+#[diag(const_eval_conditionally_const_call)]
+pub(crate) struct ConditionallyConstCall {
+    #[primary_span]
+    pub span: Span,
+    pub def_path_str: String,
+    pub def_descr: &'static str,
+    pub kind: ConstContext,
+}
+
+#[derive(Diagnostic)]
 #[diag(const_eval_non_const_fn_call, code = E0015)]
 pub(crate) struct NonConstFnCall {
     #[primary_span]
diff --git a/tests/ui/traits/const-traits/cross-crate.rs b/tests/ui/traits/const-traits/cross-crate.rs
index 9558ec6164e..b07aa8944c0 100644
--- a/tests/ui/traits/const-traits/cross-crate.rs
+++ b/tests/ui/traits/const-traits/cross-crate.rs
@@ -18,11 +18,9 @@ const fn const_context() {
     #[cfg(any(stocknc, gatednc))]
     NonConst.func();
     //[stocknc]~^ ERROR: cannot call
-    //[stocknc]~| ERROR: cannot call
-    //[gatednc]~^^^ ERROR: the trait bound
+    //[gatednc]~^^ ERROR: the trait bound
     Const.func();
     //[stock,stocknc]~^ ERROR: cannot call
-    //[stock,stocknc]~| ERROR: cannot call
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/cross-crate.stock.stderr b/tests/ui/traits/const-traits/cross-crate.stock.stderr
index b35891071b0..d26228f6958 100644
--- a/tests/ui/traits/const-traits/cross-crate.stock.stderr
+++ b/tests/ui/traits/const-traits/cross-crate.stock.stderr
@@ -1,28 +1,8 @@
-error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:23:11
+error: cannot call conditionally-const method `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
+  --> $DIR/cross-crate.rs:22:5
    |
 LL |     Const.func();
-   |           ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
-
-error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:23:11
-   |
-LL |     Const.func();
-   |           ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
+   |     ^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr
index 89de89159db..9b372860262 100644
--- a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr
+++ b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr
@@ -1,53 +1,14 @@
-error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:19:14
+error: cannot call conditionally-const method `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
+  --> $DIR/cross-crate.rs:19:5
    |
 LL |     NonConst.func();
-   |              ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
-
-error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:19:14
-   |
-LL |     NonConst.func();
-   |              ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
+   |     ^^^^^^^^^^^^^^^
 
-error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:23:11
+error: cannot call conditionally-const method `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
+  --> $DIR/cross-crate.rs:22:5
    |
 LL |     Const.func();
-   |           ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
-
-error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:23:11
-   |
-LL |     Const.func();
-   |           ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
+   |     ^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.rs b/tests/ui/traits/const-traits/staged-api-user-crate.rs
index c820d1ff47c..7587042cf27 100644
--- a/tests/ui/traits/const-traits/staged-api-user-crate.rs
+++ b/tests/ui/traits/const-traits/staged-api-user-crate.rs
@@ -10,8 +10,7 @@ fn non_const_context() {
 
 const fn stable_const_context() {
     Unstable::func();
-    //~^ ERROR cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
-    //~| ERROR cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
+    //~^ ERROR cannot call conditionally-const associated function `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.stderr b/tests/ui/traits/const-traits/staged-api-user-crate.stderr
index 24cdb1d3d5a..2bce230ffdf 100644
--- a/tests/ui/traits/const-traits/staged-api-user-crate.stderr
+++ b/tests/ui/traits/const-traits/staged-api-user-crate.stderr
@@ -1,28 +1,8 @@
-error[E0015]: cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
+error: cannot call conditionally-const associated function `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
   --> $DIR/staged-api-user-crate.rs:12:5
    |
 LL |     Unstable::func();
    |     ^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
-
-error[E0015]: cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
-  --> $DIR/staged-api-user-crate.rs:12:5
-   |
-LL |     Unstable::func();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/staged-api.rs b/tests/ui/traits/const-traits/staged-api.rs
index 401a81d8142..755a4e456bc 100644
--- a/tests/ui/traits/const-traits/staged-api.rs
+++ b/tests/ui/traits/const-traits/staged-api.rs
@@ -1,10 +1,11 @@
-//@ revisions: stable unstable
+//! Checks whether we are properly enforcing recursive const stability for trait calls.
 //@ 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(unstable)] // The feature from the ./auxiliary/staged-api.rs file.
+#![feature(local_feature)]
 #![feature(const_trait_impl)]
 #![feature(staged_api)]
+#![feature(rustc_allow_const_fn_unstable)]
 #![stable(feature = "rust1", since = "1.0.0")]
 
 //@ aux-build: staged-api.rs
@@ -16,13 +17,16 @@ use staged_api::*;
 pub struct Foo;
 
 #[stable(feature = "rust1", 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"))]
+#[rustc_const_unstable(feature = "local_feature", issue = "none")]
 impl const MyTrait for Foo {
-    //[stable]~^ ERROR trait implementations cannot be const stable yet
     fn func() {}
 }
 
+#[rustc_allow_const_fn_unstable(const_trait_impl)]
+const fn conditionally_const<T: ~const MyTrait>() {
+    T::func();
+}
+
 // Const stability has no impact on usage in non-const contexts.
 fn non_const_context() {
     Unstable::func();
@@ -32,43 +36,35 @@ fn non_const_context() {
 #[unstable(feature = "none", issue = "none")]
 const fn const_context() {
     Unstable::func();
-    //[unstable]~^ ERROR cannot use `#[feature(unstable)]`
-    //[stable]~^^ ERROR not yet stable as a const fn
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
     Foo::func();
-    //[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.
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
     Unstable2::func();
-    //~^ ERROR not yet stable as a const fn
-    // ^ fails, because the `unstable2` feature is not active
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
+    conditionally_const::<Foo>();
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))]
+#[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();
-    //[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
+    conditionally_const::<Foo>();
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "cheese", since = "1.0.0")]
 const fn stable_const_context() {
     Unstable::func();
-    //[unstable]~^ ERROR cannot use `#[feature(unstable)]`
-    //[stable]~^^ ERROR not yet stable as a const fn
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
     Foo::func();
-    //[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 cannot use `#[feature(local_feature)]`
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
+    const_context_not_const_stable();
+    //~^ ERROR cannot use `#[feature(local_feature)]`
+    conditionally_const::<Foo>();
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/staged-api.stable.stderr b/tests/ui/traits/const-traits/staged-api.stable.stderr
deleted file mode 100644
index 8f491b2f182..00000000000
--- a/tests/ui/traits/const-traits/staged-api.stable.stderr
+++ /dev/null
@@ -1,89 +0,0 @@
-error: trait implementations cannot be const stable yet
-  --> $DIR/staged-api.rs:21:1
-   |
-LL | / impl const MyTrait for Foo {
-LL | |
-LL | |     fn func() {}
-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:48:1
-   |
-LL | / pub const fn const_context_not_const_stable() {
-LL | |
-LL | |     Unstable::func();
-LL | |
-...  |
-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
-   |
-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:37: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:41: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:50: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:52: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:55: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:63: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:66: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 10 previous errors
-
diff --git a/tests/ui/traits/const-traits/staged-api.stderr b/tests/ui/traits/const-traits/staged-api.stderr
new file mode 100644
index 00000000000..29aafa4e0f3
--- /dev/null
+++ b/tests/ui/traits/const-traits/staged-api.stderr
@@ -0,0 +1,139 @@
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:38:5
+   |
+LL |     Unstable::func();
+   |     ^^^^^^^^^^^^^^^^
+   |
+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_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(const_trait_impl)]
+LL | const fn const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:40:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+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_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(const_trait_impl)]
+LL | const fn const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:42:5
+   |
+LL |     Unstable2::func();
+   |     ^^^^^^^^^^^^^^^^^
+   |
+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_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(const_trait_impl)]
+LL | const fn const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:44:5
+   |
+LL |     conditionally_const::<Foo>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+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_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(const_trait_impl)]
+LL | const fn const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:60:5
+   |
+LL |     Unstable::func();
+   |     ^^^^^^^^^^^^^^^^
+   |
+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 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(const_trait_impl)]
+LL | const fn stable_const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:62:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+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 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(const_trait_impl)]
+LL | const fn stable_const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
+  --> $DIR/staged-api.rs:64:5
+   |
+LL |     const_context_not_const_stable();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:66:5
+   |
+LL |     conditionally_const::<Foo>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+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 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(const_trait_impl)]
+LL | const fn stable_const_context() {
+   |
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/traits/const-traits/staged-api.unstable.stderr b/tests/ui/traits/const-traits/staged-api.unstable.stderr
deleted file mode 100644
index 76275452e90..00000000000
--- a/tests/ui/traits/const-traits/staged-api.unstable.stderr
+++ /dev/null
@@ -1,108 +0,0 @@
-error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
-  --> $DIR/staged-api.rs:34:5
-   |
-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() {
-   |
-
-error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
-  --> $DIR/staged-api.rs:37:5
-   |
-LL |     Foo::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(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:41:5
-   |
-LL |     Unstable2::func();
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(unstable2)]` to the crate attributes to enable
-
-error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:55: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:63:5
-   |
-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 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: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
-  --> $DIR/staged-api.rs:66:5
-   |
-LL |     Foo::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 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 function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
-  --> $DIR/staged-api.rs:70:5
-   |
-LL |     const_context_not_const_stable()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 7 previous errors
-