about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBoxy <rust@boxyuwu.dev>2024-11-12 02:54:03 +0000
committerBoxy <rust@boxyuwu.dev>2024-11-12 02:54:03 +0000
commitbea0148ac62758a99dcc2ac2cc2efedacb8881bf (patch)
tree1e3cf15272da0fb53f45fc9521b626509467af14
parent81eef2d362a6f03db6f8928f82d94298d31eb81b (diff)
downloadrust-bea0148ac62758a99dcc2ac2cc2efedacb8881bf.tar.gz
rust-bea0148ac62758a99dcc2ac2cc2efedacb8881bf.zip
Consolidate type system const evaluation under `traits::evaluate_const`
mew
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs136
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs20
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs59
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs36
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs62
-rw-r--r--compiler/rustc_next_trait_solver/src/delegate.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs6
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs28
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs31
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs52
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs213
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs21
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_normalize.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs2
-rw-r--r--tests/crashes/118545.rs8
-rw-r--r--tests/crashes/128232.rs15
-rw-r--r--tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.rs12
-rw-r--r--tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.stderr10
-rw-r--r--tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs19
-rw-r--r--tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr39
-rw-r--r--tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs36
-rw-r--r--tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr93
-rw-r--r--tests/ui/traits/const-traits/const-trait-bounds.rs32
-rw-r--r--tests/ui/traits/const-traits/const-trait-bounds.stderr29
31 files changed, 434 insertions, 569 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index ce0ab8a913b..c290f96dfdb 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1491,7 +1491,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
         } else if self.tcx.features().generic_const_exprs() {
-            ct.normalize_internal(self.tcx, self.param_env)
+            rustc_trait_selection::traits::evaluate_const(&self.infcx, ct, self.param_env)
         } else {
             ct
         }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index fc54d69449f..12df4a10e63 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -25,10 +25,10 @@ use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_macros::extension;
 pub use rustc_macros::{TypeFoldable, TypeVisitable};
+use rustc_middle::bug;
 use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::traits::select;
 pub use rustc_middle::ty::IntVarValue;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -40,7 +40,6 @@ use rustc_middle::ty::{
     self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
     GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode,
 };
-use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 use rustc_span::symbol::Symbol;
 use rustc_type_ir::solve::Reveal;
@@ -1279,84 +1278,6 @@ impl<'tcx> InferCtxt<'tcx> {
         u
     }
 
-    pub fn try_const_eval_resolve(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        unevaluated: ty::UnevaluatedConst<'tcx>,
-        span: Span,
-    ) -> Result<ty::Const<'tcx>, ErrorHandled> {
-        match self.const_eval_resolve(param_env, unevaluated, span) {
-            Ok(Ok(val)) => Ok(ty::Const::new_value(
-                self.tcx,
-                val,
-                self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args),
-            )),
-            Ok(Err(bad_ty)) => {
-                let tcx = self.tcx;
-                let def_id = unevaluated.def;
-                span_bug!(
-                    tcx.def_span(def_id),
-                    "unable to construct a valtree for the unevaluated constant {:?}: type {bad_ty} is not valtree-compatible",
-                    unevaluated
-                );
-            }
-            Err(err) => Err(err),
-        }
-    }
-
-    /// Resolves and evaluates a constant.
-    ///
-    /// The constant can be located on a trait like `<A as B>::C`, in which case the given
-    /// generic parameters and environment are used to resolve the constant. Alternatively if the
-    /// constant has generic parameters in scope the instantiations are used to evaluate the value
-    /// of the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
-    /// constant `bar::<T>()` requires a instantiation for `T`, if the instantiation for `T` is
-    /// still too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
-    /// returned.
-    ///
-    /// This handles inferences variables within both `param_env` and `args` by
-    /// performing the operation on their respective canonical forms.
-    #[instrument(skip(self), level = "debug")]
-    pub fn const_eval_resolve(
-        &self,
-        mut param_env: ty::ParamEnv<'tcx>,
-        unevaluated: ty::UnevaluatedConst<'tcx>,
-        span: Span,
-    ) -> EvalToValTreeResult<'tcx> {
-        let mut args = self.resolve_vars_if_possible(unevaluated.args);
-        debug!(?args);
-
-        // Postpone the evaluation of constants whose args depend on inference
-        // variables
-        let tcx = self.tcx;
-        if args.has_non_region_infer() {
-            if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? {
-                let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, args));
-                if let Err(e) = ct.error_reported() {
-                    return Err(ErrorHandled::Reported(e.into(), span));
-                } else if ct.has_non_region_infer() || ct.has_non_region_param() {
-                    return Err(ErrorHandled::TooGeneric(span));
-                } else {
-                    args = replace_param_and_infer_args_with_placeholder(tcx, args);
-                }
-            } else {
-                args = GenericArgs::identity_for_item(tcx, unevaluated.def);
-                param_env = tcx.param_env(unevaluated.def);
-            }
-        }
-
-        let param_env_erased = tcx.erase_regions(param_env);
-        let args_erased = tcx.erase_regions(args);
-        debug!(?param_env_erased);
-        debug!(?args_erased);
-
-        let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, args: args_erased };
-
-        // The return value is the evaluated value which doesn't contain any reference to inference
-        // variables, thus we don't need to instantiate back the original values.
-        tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span)
-    }
-
     /// The returned function is used in a fast path. If it returns `true` the variable is
     /// unchanged, `false` indicates that the status is unknown.
     #[inline]
@@ -1622,61 +1543,6 @@ impl RegionVariableOrigin {
     }
 }
 
-/// Replaces args that reference param or infer variables with suitable
-/// placeholders. This function is meant to remove these param and infer
-/// args when they're not actually needed to evaluate a constant.
-fn replace_param_and_infer_args_with_placeholder<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    args: GenericArgsRef<'tcx>,
-) -> GenericArgsRef<'tcx> {
-    struct ReplaceParamAndInferWithPlaceholder<'tcx> {
-        tcx: TyCtxt<'tcx>,
-        idx: u32,
-    }
-
-    impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceParamAndInferWithPlaceholder<'tcx> {
-        fn cx(&self) -> TyCtxt<'tcx> {
-            self.tcx
-        }
-
-        fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-            if let ty::Infer(_) = t.kind() {
-                let idx = {
-                    let idx = self.idx;
-                    self.idx += 1;
-                    idx
-                };
-                Ty::new_placeholder(self.tcx, ty::PlaceholderType {
-                    universe: ty::UniverseIndex::ROOT,
-                    bound: ty::BoundTy {
-                        var: ty::BoundVar::from_u32(idx),
-                        kind: ty::BoundTyKind::Anon,
-                    },
-                })
-            } else {
-                t.super_fold_with(self)
-            }
-        }
-
-        fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
-            if let ty::ConstKind::Infer(_) = c.kind() {
-                ty::Const::new_placeholder(self.tcx, ty::PlaceholderConst {
-                    universe: ty::UniverseIndex::ROOT,
-                    bound: ty::BoundVar::from_u32({
-                        let idx = self.idx;
-                        self.idx += 1;
-                        idx
-                    }),
-                })
-            } else {
-                c.super_fold_with(self)
-            }
-        }
-    }
-
-    args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 })
-}
-
 impl<'tcx> InferCtxt<'tcx> {
     /// Given a [`hir::Block`], get the span of its last expression or
     /// statement, peeling off any inner blocks.
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 1ae0bd6740d..757034fe30a 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -1,17 +1,17 @@
 use std::fmt::{self, Debug, Display, Formatter};
 
-use either::Either;
 use rustc_abi::{HasDataLayout, Size};
 use rustc_hir::def_id::DefId;
 use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_session::RemapFileNameExt;
 use rustc_session::config::RemapPathScopeComponents;
 use rustc_span::{DUMMY_SP, Span};
+use rustc_type_ir::visit::TypeVisitableExt;
 
 use crate::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, Scalar, alloc_range};
 use crate::mir::{Promoted, pretty_print_const_value};
 use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
-use crate::ty::{self, GenericArgsRef, ScalarInt, Ty, TyCtxt};
+use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt};
 
 ///////////////////////////////////////////////////////////////////////////
 /// Evaluated Constants
@@ -319,15 +319,13 @@ impl<'tcx> Const<'tcx> {
     ) -> Result<ConstValue<'tcx>, ErrorHandled> {
         match self {
             Const::Ty(_, c) => {
-                // We want to consistently have a "clean" value for type system constants (i.e., no
-                // data hidden in the padding), so we always go through a valtree here.
-                match c.eval_valtree(tcx, param_env, span) {
-                    Ok((ty, val)) => Ok(tcx.valtree_to_const_val((ty, val))),
-                    Err(Either::Left(_bad_ty)) => Err(tcx
-                        .dcx()
-                        .delayed_bug("`mir::Const::eval` called on a non-valtree-compatible type")
-                        .into()),
-                    Err(Either::Right(e)) => Err(e),
+                if c.has_non_region_param() {
+                    return Err(ErrorHandled::TooGeneric(span));
+                }
+
+                match c.kind() {
+                    ConstKind::Value(ty, val) => Ok(tcx.valtree_to_const_val((ty, val))),
+                    _ => Err(tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body").into()),
                 }
             }
             Const::Unevaluated(uneval, _) => {
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 5ab85a69ce6..5689f3d4265 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,4 +1,3 @@
-use either::Either;
 use rustc_data_structures::intern::Interned;
 use rustc_error_messages::MultiSpan;
 use rustc_hir::def::{DefKind, Res};
@@ -9,7 +8,7 @@ use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
 use tracing::{debug, instrument};
 
 use crate::middle::resolve_bound_vars as rbv;
-use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar};
+use crate::mir::interpret::{LitToConstInput, Scalar};
 use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
 
 mod int;
@@ -18,7 +17,7 @@ mod valtree;
 
 pub use int::*;
 pub use kind::*;
-use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
+use rustc_span::{DUMMY_SP, ErrorGuaranteed};
 pub use valtree::*;
 
 pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
@@ -363,60 +362,6 @@ impl<'tcx> Const<'tcx> {
         Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
     }
 
-    /// Returns the evaluated constant as a valtree;
-    /// if that fails due to a valtree-incompatible type, indicate which type that is
-    /// by returning `Err(Left(bad_type))`.
-    #[inline]
-    pub fn eval_valtree(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-        span: Span,
-    ) -> Result<(Ty<'tcx>, ValTree<'tcx>), Either<Ty<'tcx>, ErrorHandled>> {
-        assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
-        match self.kind() {
-            ConstKind::Unevaluated(unevaluated) => {
-                // FIXME(eddyb) maybe the `const_eval_*` methods should take
-                // `ty::ParamEnvAnd` instead of having them separate.
-                let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env);
-                // try to resolve e.g. associated constants to their definition on an impl, and then
-                // evaluate the const.
-                match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span) {
-                    Ok(Ok(c)) => {
-                        Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c))
-                    }
-                    Ok(Err(bad_ty)) => Err(Either::Left(bad_ty)),
-                    Err(err) => Err(Either::Right(err)),
-                }
-            }
-            ConstKind::Value(ty, val) => Ok((ty, val)),
-            ConstKind::Error(g) => Err(Either::Right(g.into())),
-            ConstKind::Param(_)
-            | ConstKind::Infer(_)
-            | ConstKind::Bound(_, _)
-            | ConstKind::Placeholder(_)
-            | ConstKind::Expr(_) => Err(Either::Right(ErrorHandled::TooGeneric(span))),
-        }
-    }
-
-    /// Normalizes the constant to a value or an error if possible.
-    #[inline]
-    pub fn normalize_internal(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
-        match self.eval_valtree(tcx, param_env, DUMMY_SP) {
-            Ok((ty, val)) => Self::new_value(tcx, val, ty),
-            Err(Either::Left(_bad_ty)) => {
-                // This can happen when we run on ill-typed code.
-                Self::new_error(
-                    tcx,
-                    tcx.dcx()
-                        .delayed_bug("`ty::Const::eval` called on a non-valtree-compatible type"),
-                )
-            }
-            Err(Either::Right(ErrorHandled::Reported(r, _span))) => Self::new_error(tcx, r.into()),
-            Err(Either::Right(ErrorHandled::TooGeneric(_span))) => self,
-        }
-    }
-
     /// Panics if self.kind != ty::ConstKind::Value
     pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) {
         match self.kind() {
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 91b764ae1d4..b3436550e8e 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -1,46 +1,12 @@
 use std::assert_matches::assert_matches;
 
-use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, extension};
+use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 
 use super::Const;
 use crate::mir;
 use crate::ty::abstract_const::CastKind;
-use crate::ty::visit::TypeVisitableExt as _;
 use crate::ty::{self, Ty, TyCtxt};
 
-#[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)]
-impl<'tcx> ty::UnevaluatedConst<'tcx> {
-    /// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
-    /// hurts performance.
-    #[inline]
-    fn prepare_for_eval(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> (ty::ParamEnv<'tcx>, Self) {
-        // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
-        // also does later, but we want to do it before checking for
-        // inference variables.
-        // Note that we erase regions *before* calling `with_reveal_all_normalized`,
-        // so that we don't try to invoke this query with
-        // any region variables.
-
-        // HACK(eddyb) when the query key would contain inference variables,
-        // attempt using identity args and `ParamEnv` instead, that will succeed
-        // when the expression doesn't depend on any parameters.
-        // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
-        // we can call `infcx.const_eval_resolve` which handles inference variables.
-        if (param_env, self).has_non_region_infer() {
-            (tcx.param_env(self.def), ty::UnevaluatedConst {
-                def: self.def,
-                args: ty::GenericArgs::identity_for_item(tcx, self.def),
-            })
-        } else {
-            (tcx.erase_regions(param_env).with_reveal_all_normalized(tcx), tcx.erase_regions(self))
-        }
-    }
-}
-
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
 #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
 pub enum ExprKind {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 983853d2de1..82632350af5 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,14 +1,13 @@
-use either::Either;
 use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_apfloat::Float;
 use rustc_hir as hir;
 use rustc_index::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
-use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree};
+use rustc_middle::{mir, span_bug};
 use rustc_span::Span;
 use rustc_trait_selection::traits::ObligationCause;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -40,7 +39,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         // of opaques defined in this function here.
         let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let mut convert = ConstToPat::new(self, id, span, infcx);
-        convert.to_pat(c, ty)
+
+        match c.kind() {
+            ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
+            ty::ConstKind::Value(_, val) => convert.valtree_to_pat(val, ty),
+            _ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c),
+        }
     }
 }
 
@@ -81,27 +85,42 @@ impl<'tcx> ConstToPat<'tcx> {
         ty.is_structural_eq_shallow(self.infcx.tcx)
     }
 
-    fn to_pat(&mut self, c: ty::Const<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
+    fn unevaluated_to_pat(
+        &mut self,
+        uv: ty::UnevaluatedConst<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Box<Pat<'tcx>> {
         trace!(self.treat_byte_string_as_slice);
         let pat_from_kind = |kind| Box::new(Pat { span: self.span, ty, kind });
 
-        // Get a valtree. If that fails, this const is definitely not valid for use as a pattern.
-        let valtree = match c.eval_valtree(self.tcx(), self.param_env, self.span) {
-            Ok((_, valtree)) => valtree,
-            Err(Either::Right(e)) => {
-                let err = match e {
-                    ErrorHandled::Reported(..) => {
-                        // Let's tell the use where this failing const occurs.
-                        self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span })
-                    }
-                    ErrorHandled::TooGeneric(_) => self
-                        .tcx()
-                        .dcx()
-                        .emit_err(ConstPatternDependsOnGenericParameter { span: self.span }),
-                };
-                return pat_from_kind(PatKind::Error(err));
+        // It's not *technically* correct to be revealing opaque types here as borrowcheck has
+        // not run yet. However, CTFE itself uses `Reveal::All` unconditionally even during
+        // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). As a
+        // result we always use a revealed env when resolving the instance to evaluate.
+        //
+        // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All`
+        // instead of having this logic here
+        let param_env =
+            self.tcx().erase_regions(self.param_env).with_reveal_all_normalized(self.tcx());
+        let uv = self.tcx().erase_regions(uv);
+
+        // try to resolve e.g. associated constants to their definition on an impl, and then
+        // evaluate the const.
+        let valtree = match self.infcx.tcx.const_eval_resolve_for_typeck(param_env, uv, self.span) {
+            Ok(Ok(c)) => c,
+            Err(ErrorHandled::Reported(_, _)) => {
+                // Let's tell the use where this failing const occurs.
+                let e = self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span });
+                return pat_from_kind(PatKind::Error(e));
             }
-            Err(Either::Left(bad_ty)) => {
+            Err(ErrorHandled::TooGeneric(_)) => {
+                let e = self
+                    .tcx()
+                    .dcx()
+                    .emit_err(ConstPatternDependsOnGenericParameter { span: self.span });
+                return pat_from_kind(PatKind::Error(e));
+            }
+            Ok(Err(bad_ty)) => {
                 // The pattern cannot be turned into a valtree.
                 let e = match bad_ty.kind() {
                     ty::Adt(def, ..) => {
@@ -128,8 +147,7 @@ impl<'tcx> ConstToPat<'tcx> {
             if !self.type_has_partial_eq_impl(ty) {
                 let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty };
                 let e = self.tcx().dcx().emit_err(err);
-                let kind = PatKind::Error(e);
-                return Box::new(Pat { span: self.span, ty, kind });
+                return pat_from_kind(PatKind::Error(e));
             }
         }
 
diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs
index f7fbfed5b8e..4ba54a2e0bf 100644
--- a/compiler/rustc_next_trait_solver/src/delegate.rs
+++ b/compiler/rustc_next_trait_solver/src/delegate.rs
@@ -29,10 +29,10 @@ pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Size
     // FIXME: Uplift the leak check into this crate.
     fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>;
 
-    fn try_const_eval_resolve(
+    fn evaluate_const(
         &self,
         param_env: <Self::Interner as Interner>::ParamEnv,
-        unevaluated: ty::UnevaluatedConst<Self::Interner>,
+        uv: ty::UnevaluatedConst<Self::Interner>,
     ) -> Option<<Self::Interner as Interner>::Const>;
 
     // FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`!
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index 8685896715e..979a3794748 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -1001,12 +1001,12 @@ where
     // Try to evaluate a const, or return `None` if the const is too generic.
     // This doesn't mean the const isn't evaluatable, though, and should be treated
     // as an ambiguity rather than no-solution.
-    pub(super) fn try_const_eval_resolve(
+    pub(super) fn evaluate_const(
         &self,
         param_env: I::ParamEnv,
-        unevaluated: ty::UnevaluatedConst<I>,
+        uv: ty::UnevaluatedConst<I>,
     ) -> Option<I::Const> {
-        self.delegate.try_const_eval_resolve(param_env, unevaluated)
+        self.delegate.evaluate_const(param_env, uv)
     }
 
     pub(super) fn is_transmutable(
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index 6793779b205..5c54656cc59 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -143,7 +143,7 @@ where
     ) -> QueryResult<I> {
         match ct.kind() {
             ty::ConstKind::Unevaluated(uv) => {
-                // We never return `NoSolution` here as `try_const_eval_resolve` emits an
+                // We never return `NoSolution` here as `evaluate_const` emits an
                 // error itself when failing to evaluate, so emitting an additional fulfillment
                 // error in that case is unnecessary noise. This may change in the future once
                 // evaluation failures are allowed to impact selection, e.g. generic const
@@ -151,7 +151,7 @@ where
 
                 // FIXME(generic_const_exprs): Implement handling for generic
                 // const expressions here.
-                if let Some(_normalized) = self.try_const_eval_resolve(param_env, uv) {
+                if let Some(_normalized) = self.evaluate_const(param_env, uv) {
                     self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 } else {
                     self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs
index 5d5597429da..8ad0bf5cdf9 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs
@@ -14,7 +14,7 @@ where
         &mut self,
         goal: Goal<I, ty::NormalizesTo<I>>,
     ) -> QueryResult<I> {
-        if let Some(normalized_const) = self.try_const_eval_resolve(
+        if let Some(normalized_const) = self.evaluate_const(
             goal.param_env,
             ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args),
         ) {
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index c53689b211d..2cc787c8bc5 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -15,7 +15,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
 use rustc_type_ir::TypingMode;
 use rustc_type_ir::solve::{Certainty, NoSolution};
 
-use crate::traits::specialization_graph;
+use crate::traits::{EvaluateConstErr, specialization_graph};
 
 #[repr(transparent)]
 pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>);
@@ -77,20 +77,19 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution)
     }
 
-    fn try_const_eval_resolve(
+    fn evaluate_const(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        unevaluated: ty::UnevaluatedConst<'tcx>,
+        uv: ty::UnevaluatedConst<'tcx>,
     ) -> Option<ty::Const<'tcx>> {
-        use rustc_middle::mir::interpret::ErrorHandled;
-        match self.const_eval_resolve(param_env, unevaluated, DUMMY_SP) {
-            Ok(Ok(val)) => Some(ty::Const::new_value(
-                self.tcx,
-                val,
-                self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args),
-            )),
-            Ok(Err(_)) | Err(ErrorHandled::TooGeneric(_)) => None,
-            Err(ErrorHandled::Reported(e, _)) => Some(ty::Const::new_error(self.tcx, e.into())),
+        let ct = ty::Const::new_unevaluated(self.tcx, uv);
+
+        match crate::traits::try_evaluate_const(&self.0, ct, param_env) {
+            Ok(ct) => Some(ct),
+            Err(EvaluateConstErr::EvaluationFailure(e)) => Some(ty::Const::new_error(self.tcx, e)),
+            Err(
+                EvaluateConstErr::InvalidConstParamTy(_) | EvaluateConstErr::HasGenericsOrInfers,
+            ) => None,
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 52ba5621d31..103f7c76a86 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -7,7 +7,6 @@ use std::iter;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
 use rustc_data_structures::unord::UnordSet;
 use rustc_infer::infer::DefineOpaqueTypes;
-use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::{Region, RegionVid};
 use tracing::debug;
 use ty::TypingMode;
@@ -761,23 +760,20 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 ty::PredicateKind::ConstEquate(c1, c2) => {
                     let evaluate = |c: ty::Const<'tcx>| {
                         if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
-                            match selcx.infcx.const_eval_resolve(
+                            let ct = super::try_evaluate_const(
+                                selcx.infcx,
+                                c,
                                 obligation.param_env,
-                                unevaluated,
-                                obligation.cause.span,
-                            ) {
-                                Ok(Ok(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args))),
-                                Ok(Err(_)) => {
-                                    let tcx = self.tcx;
-                                    let reported =
-                                        tcx.dcx().emit_err(UnableToConstructConstantValue {
-                                            span: tcx.def_span(unevaluated.def),
-                                            unevaluated,
-                                        });
-                                    Err(ErrorHandled::Reported(reported.into(), tcx.def_span(unevaluated.def)))
-                                }
-                                Err(err) => Err(err),
+                            );
+
+                            if let Err(EvaluateConstErr::InvalidConstParamTy(_)) = ct {
+                                self.tcx.dcx().emit_err(UnableToConstructConstantValue {
+                                    span: self.tcx.def_span(unevaluated.def),
+                                    unevaluated,
+                                });
                             }
+
+                            ct
                         } else {
                             Ok(c)
                         }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 1be3c964454..15eb5d74cbf 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -12,13 +12,13 @@
 use rustc_hir::def::DefKind;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::bug;
-use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitable, TypeVisitableExt, TypeVisitor};
 use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument};
 
+use super::EvaluateConstErr;
 use crate::traits::ObligationCtxt;
 
 /// Check if a given constant can be evaluated.
@@ -68,16 +68,18 @@ pub fn is_const_evaluatable<'tcx>(
                 // here.
                 tcx.dcx().span_bug(span, "evaluating `ConstKind::Expr` is not currently supported");
             }
-            ty::ConstKind::Unevaluated(uv) => {
-                let concrete = infcx.const_eval_resolve(param_env, uv, span);
-                match concrete {
-                    Err(ErrorHandled::TooGeneric(_)) => {
+            ty::ConstKind::Unevaluated(_) => {
+                match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) {
+                    Err(EvaluateConstErr::HasGenericsOrInfers) => {
                         Err(NotConstEvaluatable::Error(infcx.dcx().span_delayed_bug(
                             span,
                             "Missing value for constant, but no error reported?",
                         )))
                     }
-                    Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())),
+                    Err(
+                        EvaluateConstErr::EvaluationFailure(e)
+                        | EvaluateConstErr::InvalidConstParamTy(e),
+                    ) => Err(NotConstEvaluatable::Error(e.into())),
                     Ok(_) => Ok(()),
                 }
             }
@@ -92,16 +94,7 @@ pub fn is_const_evaluatable<'tcx>(
             _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
         };
 
-        // FIXME: We should only try to evaluate a given constant here if it is fully concrete
-        // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
-        //
-        // We previously did not check this, so we only emit a future compat warning if
-        // const evaluation succeeds and the given constant is still polymorphic for now
-        // and hopefully soon change this to an error.
-        //
-        // See #74595 for more details about this.
-        let concrete = infcx.const_eval_resolve(param_env, uv, span);
-        match concrete {
+        match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) {
             // If we're evaluating a generic foreign constant, under a nightly compiler while
             // the current crate does not enable `feature(generic_const_exprs)`, abort
             // compilation with a useful error.
@@ -130,7 +123,7 @@ pub fn is_const_evaluatable<'tcx>(
                     .emit()
             }
 
-            Err(ErrorHandled::TooGeneric(_)) => {
+            Err(EvaluateConstErr::HasGenericsOrInfers) => {
                 let err = if uv.has_non_region_infer() {
                     NotConstEvaluatable::MentionsInfer
                 } else if uv.has_non_region_param() {
@@ -145,7 +138,9 @@ pub fn is_const_evaluatable<'tcx>(
 
                 Err(err)
             }
-            Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())),
+            Err(
+                EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e),
+            ) => Err(NotConstEvaluatable::Error(e.into())),
             Ok(_) => Ok(()),
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 21141f6e18f..2ec5f0d2249 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -10,7 +10,6 @@ use rustc_infer::traits::{
     TraitEngine,
 };
 use rustc_middle::bug;
-use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode};
@@ -26,6 +25,7 @@ use super::{
 };
 use crate::error_reporting::InferCtxtErrorExt;
 use crate::infer::{InferCtxt, TyOrConstInferVar};
+use crate::traits::EvaluateConstErr;
 use crate::traits::normalize::normalize_with_depth_to;
 use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _};
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
@@ -664,23 +664,25 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
 
                     let mut evaluate = |c: Const<'tcx>| {
                         if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
-                            match self.selcx.infcx.try_const_eval_resolve(
+                            match super::try_evaluate_const(
+                                self.selcx.infcx,
+                                c,
                                 obligation.param_env,
-                                unevaluated,
-                                obligation.cause.span,
                             ) {
                                 Ok(val) => Ok(val),
-                                Err(e) => {
-                                    match e {
-                                        ErrorHandled::TooGeneric(..) => {
-                                            stalled_on.extend(unevaluated.args.iter().filter_map(
-                                                TyOrConstInferVar::maybe_from_generic_arg,
-                                            ));
-                                        }
-                                        _ => {}
-                                    }
-                                    Err(e)
+                                e @ Err(EvaluateConstErr::HasGenericsOrInfers) => {
+                                    stalled_on.extend(
+                                        unevaluated
+                                            .args
+                                            .iter()
+                                            .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
+                                    );
+                                    e
                                 }
+                                e @ Err(
+                                    EvaluateConstErr::EvaluationFailure(_)
+                                    | EvaluateConstErr::InvalidConstParamTy(_),
+                                ) => e,
                             }
                         } else {
                             Ok(c)
@@ -707,14 +709,20 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                                 }
                             }
                         }
-                        (Err(ErrorHandled::Reported(reported, _)), _)
-                        | (_, Err(ErrorHandled::Reported(reported, _))) => ProcessResult::Error(
-                            FulfillmentErrorCode::Select(SelectionError::NotConstEvaluatable(
-                                NotConstEvaluatable::Error(reported.into()),
-                            )),
-                        ),
-                        (Err(ErrorHandled::TooGeneric(_)), _)
-                        | (_, Err(ErrorHandled::TooGeneric(_))) => {
+                        (Err(EvaluateConstErr::InvalidConstParamTy(e)), _)
+                        | (_, Err(EvaluateConstErr::InvalidConstParamTy(e))) => {
+                            ProcessResult::Error(FulfillmentErrorCode::Select(
+                                SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(e)),
+                            ))
+                        }
+                        (Err(EvaluateConstErr::EvaluationFailure(e)), _)
+                        | (_, Err(EvaluateConstErr::EvaluationFailure(e))) => {
+                            ProcessResult::Error(FulfillmentErrorCode::Select(
+                                SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(e)),
+                            ))
+                        }
+                        (Err(EvaluateConstErr::HasGenericsOrInfers), _)
+                        | (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => {
                             if c1.has_non_region_infer() || c2.has_non_region_infer() {
                                 ProcessResult::Unchanged
                             } else {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 436c0fabd29..17636d432ae 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -27,6 +27,7 @@ use std::fmt::Debug;
 use std::ops::ControlFlow;
 
 use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def::DefKind;
 pub use rustc_infer::traits::*;
 use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
@@ -34,11 +35,11 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::{
-    self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, TypingMode,
-    Upcast,
+    self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperFoldable,
+    TypeSuperVisitable, TypingMode, Upcast,
 };
-use rustc_span::Span;
 use rustc_span::def_id::DefId;
+use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument};
 
 pub use self::coherence::{
@@ -366,11 +367,23 @@ pub fn normalize_param_env_or_error<'tcx>(
                     if c.has_escaping_bound_vars() {
                         return ty::Const::new_misc_error(self.0);
                     }
+
                     // While it is pretty sus to be evaluating things with an empty param env, it
                     // should actually be okay since without `feature(generic_const_exprs)` the only
                     // const arguments that have a non-empty param env are array repeat counts. These
                     // do not appear in the type system though.
-                    c.normalize_internal(self.0, ty::ParamEnv::empty())
+                    if let ty::ConstKind::Unevaluated(uv) = c.kind()
+                        && self.0.def_kind(uv.def) == DefKind::AnonConst
+                    {
+                        let infcx = self.0.infer_ctxt().build(TypingMode::non_body_analysis());
+                        let c = evaluate_const(&infcx, c, ty::ParamEnv::empty());
+                        // We should never wind up with any `infcx` local state when normalizing anon consts
+                        // under min const generics.
+                        assert!(!c.has_infer() && !c.has_placeholders());
+                        return c;
+                    }
+
+                    c
                 }
             }
 
@@ -474,6 +487,198 @@ pub fn normalize_param_env_or_error<'tcx>(
     ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal())
 }
 
+#[derive(Debug)]
+pub enum EvaluateConstErr {
+    /// The constant being evaluated was either a generic parameter or inference variable, *or*,
+    /// some unevaluated constant with either generic parameters or inference variables in its
+    /// generic arguments.
+    HasGenericsOrInfers,
+    /// The type this constant evalauted to is not valid for use in const generics. This should
+    /// always result in an error when checking the constant is correctly typed for the parameter
+    /// it is an argument to, so a bug is delayed when encountering this.
+    InvalidConstParamTy(ErrorGuaranteed),
+    /// CTFE failed to evaluate the constant in some unrecoverable way (e.g. encountered a `panic!`).
+    /// This is also used when the constant was already tainted by error.
+    EvaluationFailure(ErrorGuaranteed),
+}
+
+// FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine
+// FIXME(generic_const_exprs): Consider accepting a `ty::UnevaluatedConst` when we are not rolling our own
+// normalization scheme
+/// Evaluates a type system constant returning a `ConstKind::Error` in cases where CTFE failed and
+/// returning the passed in constant if it was not fully concrete (i.e. depended on generic parameters
+/// or inference variables)
+///
+/// You should not call this function unless you are implementing normalization itself. Prefer to use
+/// `normalize_erasing_regions` or the `normalize` functions on `ObligationCtxt`/`FnCtxt`/`InferCtxt`.
+pub fn evaluate_const<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    ct: ty::Const<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> ty::Const<'tcx> {
+    match try_evaluate_const(infcx, ct, param_env) {
+        Ok(ct) => ct,
+        Err(EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e)) => {
+            ty::Const::new_error(infcx.tcx, e)
+        }
+        Err(EvaluateConstErr::HasGenericsOrInfers) => ct,
+    }
+}
+
+// FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine
+// FIXME(generic_const_exprs): Consider accepting a `ty::UnevaluatedConst` when we are not rolling our own
+// normalization scheme
+/// Evaluates a type system constant making sure to not allow constants that depend on generic parameters
+/// or inference variables to succeed in evaluating.
+///
+/// You should not call this function unless you are implementing normalization itself. Prefer to use
+/// `normalize_erasing_regions` or the `normalize` functions on `ObligationCtxt`/`FnCtxt`/`InferCtxt`.
+#[instrument(level = "debug", skip(infcx), ret)]
+pub fn try_evaluate_const<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    ct: ty::Const<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> Result<ty::Const<'tcx>, EvaluateConstErr> {
+    let tcx = infcx.tcx;
+    let ct = infcx.resolve_vars_if_possible(ct);
+    debug!(?ct);
+
+    match ct.kind() {
+        ty::ConstKind::Value(..) => Ok(ct),
+        ty::ConstKind::Error(e) => Err(EvaluateConstErr::EvaluationFailure(e)),
+        ty::ConstKind::Param(_)
+        | ty::ConstKind::Infer(_)
+        | ty::ConstKind::Bound(_, _)
+        | ty::ConstKind::Placeholder(_)
+        | ty::ConstKind::Expr(_) => Err(EvaluateConstErr::HasGenericsOrInfers),
+        ty::ConstKind::Unevaluated(uv) => {
+            // Postpone evaluation of constants that depend on generic parameters or inference variables.
+            let (args, param_env) = if tcx.features().generic_const_exprs()
+                && uv.has_non_region_infer()
+            {
+                // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
+                // inference variables and generic parameters to show up in `ty::Const` even though the anon const
+                // does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
+                match tcx.thir_abstract_const(uv.def) {
+                    Ok(Some(ct)) => {
+                        let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
+                        if let Err(e) = ct.error_reported() {
+                            return Err(EvaluateConstErr::EvaluationFailure(e));
+                        } else if ct.has_non_region_infer() || ct.has_non_region_param() {
+                            // If the anon const *does* actually use generic parameters or inference variables from
+                            // the generic arguments provided for it, then we should *not* attempt to evaluate it.
+                            return Err(EvaluateConstErr::HasGenericsOrInfers);
+                        } else {
+                            (replace_param_and_infer_args_with_placeholder(tcx, uv.args), param_env)
+                        }
+                    }
+                    Err(_) | Ok(None) => {
+                        let args = GenericArgs::identity_for_item(tcx, uv.def);
+                        let param_env = tcx.param_env(uv.def);
+                        (args, param_env)
+                    }
+                }
+            } else {
+                // FIXME: We don't check anything on stable as the only way we can wind up with
+                // an unevaluated constant containing generic parameters is through array repeat
+                // expression counts which have a future compat lint for usage of generic parameters
+                // instead of a hard error.
+                //
+                // This codepath is however also reachable by `generic_const_exprs` and some other
+                // feature gates which allow constants in the type system to use generic parameters.
+                // In theory we should be checking for generic parameters here and returning an error
+                // in such cases.
+                (uv.args, param_env)
+            };
+            let uv = ty::UnevaluatedConst::new(uv.def, args);
+
+            // It's not *technically* correct to be revealing opaque types here as we could still be
+            // before borrowchecking. However, CTFE itself uses `Reveal::All` unconditionally even during
+            // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). As a result we
+            // always use a revealed env when resolving the instance to evaluate.
+            //
+            // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All`
+            // instead of having this logic here
+            let env = tcx.erase_regions(param_env).with_reveal_all_normalized(tcx);
+            let erased_uv = tcx.erase_regions(uv);
+
+            use rustc_middle::mir::interpret::ErrorHandled;
+            match tcx.const_eval_resolve_for_typeck(env, erased_uv, DUMMY_SP) {
+                Ok(Ok(val)) => Ok(ty::Const::new_value(
+                    tcx,
+                    val,
+                    tcx.type_of(uv.def).instantiate(tcx, uv.args),
+                )),
+                Ok(Err(_)) => {
+                    let e = tcx.dcx().delayed_bug(
+                        "Type system constant with non valtree'able type evaluated but no error emitted",
+                    );
+                    Err(EvaluateConstErr::InvalidConstParamTy(e))
+                }
+                Err(ErrorHandled::Reported(info, _)) => {
+                    Err(EvaluateConstErr::EvaluationFailure(info.into()))
+                }
+                Err(ErrorHandled::TooGeneric(_)) => Err(EvaluateConstErr::HasGenericsOrInfers),
+            }
+        }
+    }
+}
+
+/// Replaces args that reference param or infer variables with suitable
+/// placeholders. This function is meant to remove these param and infer
+/// args when they're not actually needed to evaluate a constant.
+fn replace_param_and_infer_args_with_placeholder<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    args: GenericArgsRef<'tcx>,
+) -> GenericArgsRef<'tcx> {
+    struct ReplaceParamAndInferWithPlaceholder<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        idx: u32,
+    }
+
+    impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceParamAndInferWithPlaceholder<'tcx> {
+        fn cx(&self) -> TyCtxt<'tcx> {
+            self.tcx
+        }
+
+        fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+            if let ty::Infer(_) = t.kind() {
+                let idx = {
+                    let idx = self.idx;
+                    self.idx += 1;
+                    idx
+                };
+                Ty::new_placeholder(self.tcx, ty::PlaceholderType {
+                    universe: ty::UniverseIndex::ROOT,
+                    bound: ty::BoundTy {
+                        var: ty::BoundVar::from_u32(idx),
+                        kind: ty::BoundTyKind::Anon,
+                    },
+                })
+            } else {
+                t.super_fold_with(self)
+            }
+        }
+
+        fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+            if let ty::ConstKind::Infer(_) = c.kind() {
+                ty::Const::new_placeholder(self.tcx, ty::PlaceholderConst {
+                    universe: ty::UniverseIndex::ROOT,
+                    bound: ty::BoundVar::from_u32({
+                        let idx = self.idx;
+                        self.idx += 1;
+                        idx
+                    }),
+                })
+            } else {
+                c.super_fold_with(self)
+            }
+        }
+    }
+
+    args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 })
+}
+
 /// Normalizes the predicates and checks whether they hold in an empty environment. If this
 /// returns true, then either normalize encountered an error or one of the predicates did not
 /// hold. Used when creating vtables to check for unsatisfiable methods. This should not be
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 954dfe93387..5c38d162712 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -418,8 +418,9 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
                 self.selcx.infcx,
                 &mut self.universes,
                 constant,
-                |constant| constant.normalize_internal(tcx, self.param_env),
+                |constant| super::evaluate_const(self.selcx.infcx, constant, self.param_env),
             )
+            .super_fold_with(self)
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index a8d701a750d..5f89894fb82 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -342,7 +342,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
             self.infcx,
             &mut self.universes,
             constant,
-            |constant| constant.normalize_internal(self.infcx.tcx, self.param_env),
+            |constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env),
         );
         debug!(?constant, ?self.param_env);
         constant.try_super_fold_with(self)
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 041cfc21267..712856e6a8f 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -403,7 +403,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let mut assume = predicate.trait_ref.args.const_at(2);
         // FIXME(min_generic_const_exprs): We should shallowly normalize this.
         if self.tcx().features().generic_const_exprs() {
-            assume = assume.normalize_internal(self.tcx(), obligation.param_env);
+            assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env)
         }
         let Some(assume) =
             rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index cffb62ab559..5b4e895189b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -22,7 +22,6 @@ use rustc_infer::infer::relate::TypeRelation;
 use rustc_infer::traits::{PredicateObligations, TraitObligation};
 use rustc_middle::bug;
 use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds};
-use rustc_middle::mir::interpret::ErrorHandled;
 pub use rustc_middle::traits::select::*;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::TypeErrorToStringExt;
@@ -50,7 +49,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener};
 use crate::solve::InferCtxtSelectExt as _;
 use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
 use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
-use crate::traits::{ProjectionCacheKey, Unimplemented, effects};
+use crate::traits::{EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects};
 
 mod _match;
 mod candidate_assembly;
@@ -931,11 +930,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
 
                     let evaluate = |c: ty::Const<'tcx>| {
-                        if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
-                            match self.infcx.try_const_eval_resolve(
+                        if let ty::ConstKind::Unevaluated(_) = c.kind() {
+                            match crate::traits::try_evaluate_const(
+                                self.infcx,
+                                c,
                                 obligation.param_env,
-                                unevaluated,
-                                obligation.cause.span,
                             ) {
                                 Ok(val) => Ok(val),
                                 Err(e) => Err(e),
@@ -961,10 +960,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 Err(_) => Ok(EvaluatedToErr),
                             }
                         }
-                        (Err(ErrorHandled::Reported(..)), _)
-                        | (_, Err(ErrorHandled::Reported(..))) => Ok(EvaluatedToErr),
-                        (Err(ErrorHandled::TooGeneric(..)), _)
-                        | (_, Err(ErrorHandled::TooGeneric(..))) => {
+                        (Err(EvaluateConstErr::InvalidConstParamTy(..)), _)
+                        | (_, Err(EvaluateConstErr::InvalidConstParamTy(..))) => Ok(EvaluatedToErr),
+                        (Err(EvaluateConstErr::EvaluationFailure(..)), _)
+                        | (_, Err(EvaluateConstErr::EvaluationFailure(..))) => Ok(EvaluatedToErr),
+                        (Err(EvaluateConstErr::HasGenericsOrInfers), _)
+                        | (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => {
                             if c1.has_non_region_infer() || c2.has_non_region_infer() {
                                 Ok(EvaluatedToAmbig)
                             } else {
diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
index 23b5f62b5ca..f8e8f2176c1 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
@@ -83,7 +83,7 @@ impl<'tcx> At<'_, 'tcx> {
 
             Ok(self.infcx.resolve_vars_if_possible(new_infer_ct))
         } else if self.infcx.tcx.features().generic_const_exprs() {
-            Ok(ct.normalize_internal(self.infcx.tcx, self.param_env))
+            Ok(super::evaluate_const(&self.infcx, ct, self.param_env))
         } else {
             Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx))
         }
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index aa8b4d88d2f..44b9d6adaaa 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
             && !item.span.from_expansion()
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && let ty::Array(element_type, cst) = ty.kind()
-            && let Ok((_, ty::ValTree::Leaf(element_count))) = cst.eval_valtree(cx.tcx, ParamEnv::empty(), item.span)
+            && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx.try_normalize_erasing_regions(ParamEnv::empty(), *cst).unwrap_or(*cst).try_to_valtree()
             && let element_count = element_count.to_target_usize(cx.tcx)
             && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
             && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
diff --git a/tests/crashes/118545.rs b/tests/crashes/118545.rs
deleted file mode 100644
index 1d4bb848bf0..00000000000
--- a/tests/crashes/118545.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #118545
-#![feature(generic_const_exprs)]
-
-struct Checked<const F: fn()>;
-
-fn foo() {}
-const _: Checked<foo> = Checked::<foo>;
-pub fn main() {}
diff --git a/tests/crashes/128232.rs b/tests/crashes/128232.rs
deleted file mode 100644
index 67f61e1b240..00000000000
--- a/tests/crashes/128232.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ known-bug: #128232
-
-#![feature(generic_const_exprs, unsized_const_params)]
-
-fn function() {}
-
-struct Wrapper<const F: fn()>;
-
-impl Wrapper<{ bar() }> {
-    fn call() {}
-}
-
-fn main() {
-    Wrapper::<function>::call;
-}
diff --git a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.rs b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.rs
new file mode 100644
index 00000000000..cea82722a0e
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.rs
@@ -0,0 +1,12 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+// Regression test for #118545
+
+struct Checked<const F: fn()>;
+//~^ ERROR: using function pointers as const generic parameters is forbidden
+
+fn foo() {}
+const _: Checked<foo> = Checked::<foo>;
+
+pub fn main() {}
diff --git a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.stderr b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.stderr
new file mode 100644
index 00000000000..71339411c84
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-1.stderr
@@ -0,0 +1,10 @@
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/non_valtreeable_const_arg-1.rs:6:25
+   |
+LL | struct Checked<const F: fn()>;
+   |                         ^^^^
+   |
+   = note: the only supported types are integers, `bool`, and `char`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs
new file mode 100644
index 00000000000..6b87ad86d4b
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs
@@ -0,0 +1,19 @@
+#![feature(generic_const_exprs, unsized_const_params)]
+#![allow(incomplete_features)]
+
+// Regression test for 128232
+
+fn function() {}
+
+struct Wrapper<const F: fn()>;
+//~^ ERROR: using function pointers as const generic parameters is forbidden
+
+impl Wrapper<{ bar() }> {
+    //~^ ERROR: cannot find function `bar` in this scope
+    fn call() {}
+}
+
+fn main() {
+    Wrapper::<function>::call;
+    //~^ ERROR: the function or associated item `call` exists for struct `Wrapper<function>`,
+}
diff --git a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr
new file mode 100644
index 00000000000..b13f76eabad
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr
@@ -0,0 +1,39 @@
+error[E0425]: cannot find function `bar` in this scope
+  --> $DIR/non_valtreeable_const_arg-2.rs:11:16
+   |
+LL | impl Wrapper<{ bar() }> {
+   |                ^^^ not found in this scope
+   |
+help: you might be missing a const parameter
+   |
+LL | impl<const bar: /* Type */> Wrapper<{ bar() }> {
+   |     +++++++++++++++++++++++
+
+error[E0741]: using function pointers as const generic parameters is forbidden
+  --> $DIR/non_valtreeable_const_arg-2.rs:8:25
+   |
+LL | struct Wrapper<const F: fn()>;
+   |                         ^^^^
+
+error[E0599]: the function or associated item `call` exists for struct `Wrapper<function>`, but its trait bounds were not satisfied
+  --> $DIR/non_valtreeable_const_arg-2.rs:17:26
+   |
+LL | struct Wrapper<const F: fn()>;
+   | ----------------------------- function or associated item `call` not found for this struct because it doesn't satisfy `Wrapper<function>: Fn<_>`
+...
+LL |     Wrapper::<function>::call;
+   |                          ^^^^ function or associated item cannot be called on `Wrapper<function>` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `Wrapper<function>: Fn<_>`
+           which is required by `&Wrapper<function>: Fn<_>`
+note: the trait `Fn` must be implemented
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `call`, perhaps you need to implement it:
+           candidate #1: `Fn`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0425, E0599, E0741.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs
deleted file mode 100644
index 6c0ac639612..00000000000
--- a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-//@ known-bug: #110395
-//@ compile-flags: -Znext-solver
-#![feature(generic_const_exprs, adt_const_params, const_trait_impl)]
-#![allow(incomplete_features)]
-
-// test `N + N` unifies with explicit function calls for non-builtin-types
-#[derive(PartialEq, Eq)]
-struct Foo(u8);
-
-impl const std::ops::Add for Foo {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self::Output {
-        self
-    }
-}
-
-struct Evaluatable<const N: Foo>;
-
-fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
-    bar::<{ std::ops::Add::add(N, N) }>();
-}
-
-fn bar<const N: Foo>() {}
-
-// test that `N + N` unifies with explicit function calls for builin-types
-struct Evaluatable2<const N: usize>;
-
-fn foo2<const N: usize>(a: Evaluatable2<{ N + N }>) {
-    bar2::<{ std::ops::Add::add(N, N) }>();
-    // FIXME(generic_const_exprs) make this not an error
-}
-
-fn bar2<const N: usize>() {}
-
-fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
deleted file mode 100644
index 882fdf0b228..00000000000
--- a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
+++ /dev/null
@@ -1,93 +0,0 @@
-error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed
-  --> $DIR/unify-op-with-fn-call.rs:3:12
-   |
-LL | #![feature(generic_const_exprs, adt_const_params, const_trait_impl)]
-   |            ^^^^^^^^^^^^^^^^^^^
-   |
-   = help: remove one of these features
-
-error: const `impl` for trait `Add` which is not marked with `#[const_trait]`
-  --> $DIR/unify-op-with-fn-call.rs:10:12
-   |
-LL | impl const std::ops::Add for Foo {
-   |            ^^^^^^^^^^^^^
-   |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
-   = note: adding a non-const method body in the future would be a breaking change
-
-error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter
-  --> $DIR/unify-op-with-fn-call.rs:18:29
-   |
-LL | struct Evaluatable<const N: Foo>;
-   |                             ^^^
-   |
-help: add `#[derive(ConstParamTy)]` to the struct
-   |
-LL + #[derive(ConstParamTy)]
-LL | struct Foo(u8);
-   |
-
-error[E0015]: cannot call non-const operator in constants
-  --> $DIR/unify-op-with-fn-call.rs:20:39
-   |
-LL | fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
-   |                                       ^^^^^
-   |
-   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-
-error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter
-  --> $DIR/unify-op-with-fn-call.rs:20:17
-   |
-LL | fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
-   |                 ^^^
-   |
-help: add `#[derive(ConstParamTy)]` to the struct
-   |
-LL + #[derive(ConstParamTy)]
-LL | struct Foo(u8);
-   |
-
-error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter
-  --> $DIR/unify-op-with-fn-call.rs:24:17
-   |
-LL | fn bar<const N: Foo>() {}
-   |                 ^^^
-   |
-help: add `#[derive(ConstParamTy)]` to the struct
-   |
-LL + #[derive(ConstParamTy)]
-LL | struct Foo(u8);
-   |
-
-error[E0284]: type annotations needed: cannot normalize `foo2<N>::{constant#0}`
-  --> $DIR/unify-op-with-fn-call.rs:29:28
-   |
-LL | fn foo2<const N: usize>(a: Evaluatable2<{ N + N }>) {
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2<N>::{constant#0}`
-
-error[E0015]: cannot call non-const fn `<Foo as Add>::add` in constants
-  --> $DIR/unify-op-with-fn-call.rs:21:13
-   |
-LL |     bar::<{ std::ops::Add::add(N, N) }>();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-
-error[E0015]: cannot call non-const fn `<usize as Add>::add` in constants
-  --> $DIR/unify-op-with-fn-call.rs:30:14
-   |
-LL |     bar2::<{ std::ops::Add::add(N, N) }>();
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-
-error[E0284]: type annotations needed: cannot normalize `foo2<N>::{constant#0}`
-  --> $DIR/unify-op-with-fn-call.rs:30:12
-   |
-LL |     bar2::<{ std::ops::Add::add(N, N) }>();
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2<N>::{constant#0}`
-
-error: aborting due to 10 previous errors
-
-Some errors have detailed explanations: E0015, E0284, E0741.
-For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const-trait-bounds.rs b/tests/ui/traits/const-traits/const-trait-bounds.rs
deleted file mode 100644
index 8722d9909ed..00000000000
--- a/tests/ui/traits/const-traits/const-trait-bounds.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-//@ known-bug: #110395
-//@ compile-flags: -Znext-solver
-// FIXME(const_trait_impl): check-pass
-#![feature(const_trait_impl, generic_const_exprs)]
-#![allow(incomplete_features)]
-
-fn main() {
-    let _ = process::<()>([()]);
-    let _ = Struct::<(), 4> { field: [1, 0] };
-}
-
-fn process<T: const Trait>(input: [(); T::make(2)]) -> [(); T::make(2)] {
-    input
-}
-
-struct Struct<T: const Trait, const P: usize>
-where
-    [u32; T::make(P)]:,
-{
-    field: [u32; T::make(P)],
-}
-
-#[const_trait]
-trait Trait {
-    fn make(input: usize) -> usize;
-}
-
-impl const Trait for () {
-    fn make(input: usize) -> usize {
-        input / 2
-    }
-}
diff --git a/tests/ui/traits/const-traits/const-trait-bounds.stderr b/tests/ui/traits/const-traits/const-trait-bounds.stderr
deleted file mode 100644
index 29a01b9d7dc..00000000000
--- a/tests/ui/traits/const-traits/const-trait-bounds.stderr
+++ /dev/null
@@ -1,29 +0,0 @@
-error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed
-  --> $DIR/const-trait-bounds.rs:4:30
-   |
-LL | #![feature(const_trait_impl, generic_const_exprs)]
-   |                              ^^^^^^^^^^^^^^^^^^^
-   |
-   = help: remove one of these features
-
-error[E0284]: type annotations needed: cannot normalize `process<T>::{constant#0}`
-  --> $DIR/const-trait-bounds.rs:12:35
-   |
-LL | fn process<T: const Trait>(input: [(); T::make(2)]) -> [(); T::make(2)] {
-   |                                   ^^^^^^^^^^^^^^^^ cannot normalize `process<T>::{constant#0}`
-
-error[E0284]: type annotations needed: cannot normalize `Struct<T, P>::field::{constant#0}`
-  --> $DIR/const-trait-bounds.rs:20:12
-   |
-LL |     field: [u32; T::make(P)],
-   |            ^^^^^^^^^^^^^^^^^ cannot normalize `Struct<T, P>::field::{constant#0}`
-
-error[E0284]: type annotations needed: cannot normalize `process<T>::{constant#1}`
-  --> $DIR/const-trait-bounds.rs:13:5
-   |
-LL |     input
-   |     ^^^^^ cannot normalize `process<T>::{constant#1}`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0284`.