From bfaf13af4e5071b09248979e51c6614bf1353f52 Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Tue, 16 Mar 2021 00:05:45 +0100
Subject: [PATCH] make unevaluated const substs optional

---
 .../rustc_codegen_cranelift/src/constant.rs   | 10 ++---
 compiler/rustc_infer/src/infer/combine.rs     | 18 ++++----
 .../src/infer/error_reporting/mod.rs          |  4 +-
 .../nice_region_error/static_impl_trait.rs    |  6 ++-
 compiler/rustc_infer/src/infer/mod.rs         | 10 ++---
 .../rustc_infer/src/infer/nll_relate/mod.rs   |  4 +-
 compiler/rustc_infer/src/infer/resolve.rs     |  4 +-
 compiler/rustc_lint/src/types.rs              |  4 +-
 .../rustc_middle/src/mir/interpret/queries.rs |  2 +-
 compiler/rustc_middle/src/query/mod.rs        |  4 ++
 compiler/rustc_middle/src/ty/consts.rs        |  3 +-
 compiler/rustc_middle/src/ty/consts/kind.rs   | 38 +++++++++++-----
 compiler/rustc_middle/src/ty/flags.rs         |  3 +-
 compiler/rustc_middle/src/ty/fold.rs          | 35 +++++++++------
 compiler/rustc_middle/src/ty/print/pretty.rs  | 43 +++++++++----------
 compiler/rustc_middle/src/ty/relate.rs        |  8 ++--
 .../rustc_middle/src/ty/structural_impls.rs   | 31 +++++++++----
 compiler/rustc_middle/src/ty/walk.rs          |  3 +-
 .../src/borrow_check/type_check/mod.rs        |  8 ++--
 compiler/rustc_mir/src/interpret/operand.rs   |  6 +--
 compiler/rustc_mir/src/interpret/util.rs      |  4 +-
 .../src/monomorphize/polymorphize.rs          | 16 +++----
 .../src/transform/check_consts/qualifs.rs     |  2 +-
 .../rustc_mir/src/transform/const_prop.rs     |  2 +-
 .../rustc_mir/src/transform/promote_consts.rs | 18 +++++---
 compiler/rustc_mir/src/util/pretty.rs         |  8 ++--
 compiler/rustc_mir_build/src/thir/cx/expr.rs  | 14 +++---
 compiler/rustc_privacy/src/lib.rs             |  4 +-
 .../rustc_trait_selection/src/opaque_types.rs |  4 +-
 .../src/traits/const_evaluatable.rs           | 11 ++---
 .../src/traits/fulfill.rs                     |  5 ++-
 .../src/traits/object_safety.rs               |  4 +-
 .../src/traits/structural_match.rs            |  4 +-
 .../rustc_trait_selection/src/traits/wf.rs    |  9 ++--
 compiler/rustc_traits/src/chalk/lowering.rs   |  9 ++--
 compiler/rustc_ty_utils/src/instance.rs       |  5 ++-
 compiler/rustc_typeck/src/check/check.rs      | 19 ++++----
 compiler/rustc_typeck/src/check/op.rs         |  4 +-
 compiler/rustc_typeck/src/check/wfcheck.rs    |  4 +-
 compiler/rustc_typeck/src/collect.rs          |  4 +-
 compiler/rustc_typeck/src/collect/type_of.rs  |  6 ++-
 .../src/constrained_generic_params.rs         |  4 +-
 src/librustdoc/clean/utils.rs                 |  2 +-
 .../clippy/clippy_lints/src/non_copy_const.rs |  6 +--
 .../clippy_lints/src/redundant_clone.rs       |  4 +-
 src/tools/clippy/clippy_utils/src/consts.rs   |  6 +--
 46 files changed, 234 insertions(+), 188 deletions(-)

diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index c87309e2222..424a0d742d1 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -129,13 +129,13 @@ pub(crate) fn codegen_constant<'tcx>(
     };
     let const_val = match const_.val {
         ConstKind::Value(const_val) => const_val,
-        ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
-            if fx.tcx.is_static(def.did) =>
+        ConstKind::Unevaluated(uv)
+            if fx.tcx.is_static(uv.def.did) =>
         {
-            assert!(substs.is_empty());
-            assert!(promoted.is_none());
+            assert!(uv.substs(fx.tcx).is_empty());
+            assert!(uv.promoted.is_none());
 
-            return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty)).to_cvalue(fx);
+            return codegen_static_ref(fx, uv.def.did, fx.layout_of(const_.ty)).to_cvalue(fx);
         }
         ConstKind::Unevaluated(unevaluated) => {
             match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) {
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 01d84e287bc..4fb3d4bdfe1 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -742,10 +742,9 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                     }
                 }
             }
-            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
-                if self.tcx().lazy_normalization() =>
-            {
-                assert_eq!(promoted, None);
+            ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => {
+                assert_eq!(uv.promoted, None);
+                let substs = uv.substs(self.tcx());
                 let substs = self.relate_with_variance(
                     ty::Variance::Invariant,
                     ty::VarianceDiagInfo::default(),
@@ -754,7 +753,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                 )?;
                 Ok(self.tcx().mk_const(ty::Const {
                     ty: c.ty,
-                    val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
+                    val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)),
                 }))
             }
             _ => relate::super_relate_consts(self, c, c),
@@ -976,10 +975,9 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
                     }
                 }
             }
-            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
-                if self.tcx().lazy_normalization() =>
-            {
-                assert_eq!(promoted, None);
+            ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => {
+                assert_eq!(uv.promoted, None);
+                let substs = uv.substs(self.tcx());
                 let substs = self.relate_with_variance(
                     ty::Variance::Invariant,
                     ty::VarianceDiagInfo::default(),
@@ -988,7 +986,7 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
                 )?;
                 Ok(self.tcx().mk_const(ty::Const {
                     ty: c.ty,
-                    val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
+                    val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)),
                 }))
             }
             _ => relate::super_relate_consts(self, c, c),
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 14fdf03e06d..299dcf5f17a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1537,8 +1537,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
 
         impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
-            fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> {
-                self.tcx
+            fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+                Some(self.tcx)
             }
 
             fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index d3d55d89db6..81059fbcb10 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -479,8 +479,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 pub(super) struct TraitObjectVisitor(pub(super) FxHashSet<DefId>);
 
 impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
-    fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> {
-        bug!("tcx_for_anon_const_substs called for TraitObjectVisitor");
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        // The default anon const substs cannot include
+        // trait objects, so we don't have to bother looking.
+        None
     }
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 9013bea749a..155abf4ef83 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -679,7 +679,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         b: ty::Unevaluated<'tcx>,
     ) -> bool {
         let canonical = self.canonicalize_query(
-            ((a.def, a.substs), (b.def, b.substs)),
+            ((a.def, a.substs(self.tcx)), (b.def, b.substs(self.tcx))),
             &mut OriginalQueryValues::default(),
         );
         debug!("canonical consts: {:?}", &canonical.value);
@@ -1592,16 +1592,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn const_eval_resolve(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        ty::Unevaluated { def, substs, promoted }: ty::Unevaluated<'tcx>,
+        unevaluated: ty::Unevaluated<'tcx>,
         span: Option<Span>,
     ) -> EvalToConstValueResult<'tcx> {
         let mut original_values = OriginalQueryValues::default();
-        let canonical = self.canonicalize_query((param_env, substs), &mut original_values);
+        let canonical = self.canonicalize_query((param_env, unevaluated), &mut original_values);
 
-        let (param_env, substs) = canonical.value;
+        let (param_env, unevaluated) = canonical.value;
         // The return value is the evaluated value which doesn't contain any reference to inference
         // variables, thus we don't need to substitute back the original values.
-        self.tcx.const_eval_resolve(param_env, ty::Unevaluated { def, substs, promoted }, span)
+        self.tcx.const_eval_resolve(param_env, unevaluated, span)
     }
 
     /// If `typ` is a type variable of some kind, resolve it one level
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 8f1ebb116fd..c211d8e94a6 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -766,8 +766,8 @@ struct ScopeInstantiator<'me, 'tcx> {
 }
 
 impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
-    fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> {
-        self.tcx
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        Some(self.tcx)
     }
 
     fn visit_binder<T: TypeFoldable<'tcx>>(
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index e5ad44c7427..4b08c2eb9c1 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -127,8 +127,8 @@ impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> {
 impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
     type BreakTy = (Ty<'tcx>, Option<Span>);
 
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        Some(self.infcx.tcx)
     }
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 1194d8edc09..5d255781639 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1160,8 +1160,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
         impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
             type BreakTy = Ty<'tcx>;
-            fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-                self.cx.tcx
+            fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+                Some(self.cx.tcx)
             }
 
             fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index fa7c0670e8c..c63613ae3af 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -38,7 +38,7 @@ impl<'tcx> TyCtxt<'tcx> {
         ct: ty::Unevaluated<'tcx>,
         span: Option<Span>,
     ) -> EvalToConstValueResult<'tcx> {
-        match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
+        match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs(self)) {
             Ok(Some(instance)) => {
                 let cid = GlobalId { instance, promoted: ct.promoted };
                 self.const_eval_global_id(param_env, cid, span)
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 68de7f29193..737b1108f50 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -114,6 +114,10 @@ rustc_queries! {
         desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param)  }
     }
 
+    query default_anon_const_substs(key: DefId) -> SubstsRef<'tcx> {
+        desc { |tcx| "computing the default generic arguments for `{}`", tcx.def_path_str(key) }
+    }
+
     /// Records the type of every item.
     query type_of(key: DefId) -> Ty<'tcx> {
         desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) }
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index c78151271c1..869b2ab9dbc 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,6 +1,5 @@
 use crate::mir::interpret::ConstValue;
 use crate::mir::interpret::{LitToConstInput, Scalar};
-use crate::ty::subst::InternalSubsts;
 use crate::ty::{self, Ty, TyCtxt};
 use crate::ty::{ParamEnv, ParamEnvAnd};
 use rustc_errors::ErrorReported;
@@ -100,7 +99,7 @@ impl<'tcx> Const<'tcx> {
             }
             _ => ty::ConstKind::Unevaluated(ty::Unevaluated {
                 def: def.to_global(),
-                substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
+                substs_: None,
                 promoted: None,
             }),
         };
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index f2db95d162b..ab2c57ac605 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -16,10 +16,23 @@ use super::ScalarInt;
 #[derive(Hash, HashStable)]
 pub struct Unevaluated<'tcx> {
     pub def: ty::WithOptConstParam<DefId>,
-    pub substs: SubstsRef<'tcx>,
+    pub substs_: Option<SubstsRef<'tcx>>,
     pub promoted: Option<Promoted>,
 }
 
+impl<'tcx> Unevaluated<'tcx> {
+    pub fn new(def: ty::WithOptConstParam<DefId>, substs: SubstsRef<'tcx>) -> Unevaluated<'tcx> {
+        Unevaluated { def, substs_: Some(substs), promoted: None }
+    }
+
+    pub fn substs(self, tcx: TyCtxt<'tcx>) -> SubstsRef<'tcx> {
+        self.substs_.unwrap_or_else(|| {
+            debug_assert_eq!(self.promoted, None);
+            tcx.default_anon_const_substs(self.def.did)
+        })
+    }
+}
+
 /// Represents a constant in Rust.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
 #[derive(Hash, HashStable)]
@@ -109,7 +122,7 @@ impl<'tcx> ConstKind<'tcx> {
         tcx: TyCtxt<'tcx>,
         param_env: ParamEnv<'tcx>,
     ) -> Option<Result<ConstValue<'tcx>, ErrorReported>> {
-        if let ConstKind::Unevaluated(Unevaluated { def, substs, promoted }) = self {
+        if let ConstKind::Unevaluated(unevaluated) = self {
             use crate::mir::interpret::ErrorHandled;
 
             // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
@@ -118,29 +131,32 @@ impl<'tcx> ConstKind<'tcx> {
             // 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.
-            let param_env_and_substs = tcx
+            let param_env_and = tcx
                 .erase_regions(param_env)
                 .with_reveal_all_normalized(tcx)
-                .and(tcx.erase_regions(substs));
+                .and(tcx.erase_regions(unevaluated));
 
             // HACK(eddyb) when the query key would contain inference variables,
             // attempt using identity substs 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.
-            let param_env_and_substs = if param_env_and_substs.needs_infer() {
-                tcx.param_env(def.did).and(InternalSubsts::identity_for_item(tcx, def.did))
+            let param_env_and = if param_env_and.needs_infer() {
+                tcx.param_env(unevaluated.def.did).and(ty::Unevaluated {
+                    def: unevaluated.def,
+                    substs_: Some(InternalSubsts::identity_for_item(tcx, unevaluated.def.did)),
+                    promoted: unevaluated.promoted,
+                })
             } else {
-                param_env_and_substs
+                param_env_and
             };
 
             // FIXME(eddyb) maybe the `const_eval_*` methods should take
-            // `ty::ParamEnvAnd<SubstsRef>` instead of having them separate.
-            let (param_env, substs) = param_env_and_substs.into_parts();
+            // `ty::ParamEnvAnd` instead of having them separate.
+            let (param_env, unevaluated) = param_env_and.into_parts();
             // try to resolve e.g. associated constants to their definition on an impl, and then
             // evaluate the const.
-            match tcx.const_eval_resolve(param_env, ty::Unevaluated { def, substs, promoted }, None)
-            {
+            match tcx.const_eval_resolve(param_env, unevaluated, None) {
                 // NOTE(eddyb) `val` contains no lifetimes/types/consts,
                 // and we use the original type, so nothing from `substs`
                 // (which may be identity substs, see above),
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 04df706d908..89cba4aab83 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -305,7 +305,8 @@ impl FlagComputation {
     }
 
     fn add_unevaluated_const(&mut self, ct: ty::Unevaluated<'tcx>) {
-        self.add_substs(ct.substs);
+        // TODO
+        self.add_substs(ct.substs_.unwrap());
         self.add_flags(TypeFlags::HAS_CT_PROJECTION);
     }
 
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 40b3ffb8955..6e70e8ddaed 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -192,9 +192,11 @@ pub trait TypeVisitor<'tcx>: Sized {
     /// Supplies the `tcx` for an unevaluated anonymous constant in case its default substs
     /// are not yet supplied.
     ///
-    /// Visitors which do not look into these substs may leave this unimplemented, so be
-    /// careful when calling this method elsewhere.
-    fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx>;
+    /// Visitors which do not look into these substs may return `None` here, in which case
+    /// `super_visit_with` completely skips the default substs. Incorrectly returning
+    /// `None` can very quickly lead to ICE or other critical bugs, so be careful and
+    /// try to return an actual `tcx` if at all possible.
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>>;
 
     fn visit_binder<T: TypeFoldable<'tcx>>(
         &mut self,
@@ -336,8 +338,8 @@ impl<'tcx> TyCtxt<'tcx> {
         {
             type BreakTy = ();
 
-            fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-                self.tcx
+            fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+                Some(self.tcx)
             }
 
             fn visit_binder<T: TypeFoldable<'tcx>>(
@@ -788,8 +790,9 @@ impl<'tcx> ValidateBoundVars<'tcx> {
 impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> {
     type BreakTy = ();
 
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        bug!("default anon const substs can't contain bound vars");
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        // Anonymous constants do not contain bound vars in their substs by default.
+        None
     }
 
     fn visit_binder<T: TypeFoldable<'tcx>>(
@@ -1006,8 +1009,9 @@ struct HasEscapingVarsVisitor {
 impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
     type BreakTy = FoundEscapingVars;
 
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        bug!("tcx_for_anon_const_substs called for HasEscpaingVarsVisitor");
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        // Anonymous constants do not contain bound vars in their substs by default.
+        None
     }
 
     fn visit_binder<T: TypeFoldable<'tcx>>(
@@ -1080,8 +1084,13 @@ struct HasTypeFlagsVisitor {
 
 impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
     type BreakTy = FoundFlags;
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        bug!("tcx_for_anon_const_substs called for HasTypeFlagsVisitor");
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        // TypeFlagsVisitor must not look into the default anon const substs
+        // as that would cause cycle errors, but we do care about them for
+        // some flags.
+        //
+        // We therefore have to be very careful here.
+        None
     }
 
     #[inline]
@@ -1164,8 +1173,8 @@ impl LateBoundRegionsCollector<'tcx> {
 }
 
 impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector<'tcx> {
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        self.tcx
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        Some(self.tcx)
     }
 
     fn visit_binder<T: TypeFoldable<'tcx>>(
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index ef999285f53..13222363096 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -927,29 +927,28 @@ pub trait PrettyPrinter<'tcx>:
         }
 
         match ct.val {
-            ty::ConstKind::Unevaluated(ty::Unevaluated {
-                def,
-                substs,
-                promoted: Some(promoted),
-            }) => {
-                p!(print_value_path(def.did, substs));
-                p!(write("::{:?}", promoted));
-            }
-            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None }) => {
-                match self.tcx().def_kind(def.did) {
-                    DefKind::Static | DefKind::Const | DefKind::AssocConst => {
-                        p!(print_value_path(def.did, substs))
-                    }
-                    _ => {
-                        if def.is_local() {
-                            let span = self.tcx().def_span(def.did);
-                            if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
-                                p!(write("{}", snip))
+            ty::ConstKind::Unevaluated(uv) => {
+                if let Some(promoted) = uv.promoted {
+                    let substs = uv.substs_.unwrap();
+                    p!(print_value_path(uv.def.did, substs));
+                    p!(write("::{:?}", promoted));
+                } else {
+                    let tcx = self.tcx();
+                    match tcx.def_kind(uv.def.did) {
+                        DefKind::Static | DefKind::Const | DefKind::AssocConst => {
+                            p!(print_value_path(uv.def.did, uv.substs(tcx)))
+                        }
+                        _ => {
+                            if uv.def.is_local() {
+                                let span = tcx.def_span(uv.def.did);
+                                if let Ok(snip) = tcx.sess.source_map().span_to_snippet(span) {
+                                    p!(write("{}", snip))
+                                } else {
+                                    print_underscore!()
+                                }
                             } else {
                                 print_underscore!()
                             }
-                        } else {
-                            print_underscore!()
                         }
                     }
                 }
@@ -2025,8 +2024,8 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
         impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> {
             type BreakTy = ();
 
-            fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-                self.tcx
+            fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+                Some(self.tcx)
             }
 
             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 9c48f05617e..c978e1de38d 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -579,7 +579,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
         (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
             if tcx.features().const_evaluatable_checked =>
         {
-            tcx.try_unify_abstract_consts(((au.def, au.substs), (bu.def, bu.substs)))
+            tcx.try_unify_abstract_consts(((au.def, au.substs(tcx)), (bu.def, bu.substs(tcx))))
         }
 
         // While this is slightly incorrect, it shouldn't matter for `min_const_generics`
@@ -591,13 +591,13 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
             let substs = relation.relate_with_variance(
                 ty::Variance::Invariant,
                 ty::VarianceDiagInfo::default(),
-                au.substs,
-                bu.substs,
+                au.substs(tcx),
+                bu.substs(tcx),
             )?;
             return Ok(tcx.mk_const(ty::Const {
                 val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                     def: au.def,
-                    substs,
+                    substs_: Some(substs),
                     promoted: au.promoted,
                 }),
                 ty: a.ty,
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index a46cac1e7f7..fe7d46240cb 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -1046,13 +1046,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
         match self {
             ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
             ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
-            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
-                ty::ConstKind::Unevaluated(ty::Unevaluated {
-                    def,
-                    substs: substs.fold_with(folder),
-                    promoted,
-                })
-            }
+            ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)),
             ty::ConstKind::Value(_)
             | ty::ConstKind::Bound(..)
             | ty::ConstKind::Placeholder(..)
@@ -1064,7 +1058,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
         match *self {
             ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
             ty::ConstKind::Param(p) => p.visit_with(visitor),
-            ty::ConstKind::Unevaluated(ct) => ct.substs.visit_with(visitor),
+            ty::ConstKind::Unevaluated(uv) => uv.visit_with(visitor),
             ty::ConstKind::Value(_)
             | ty::ConstKind::Bound(..)
             | ty::ConstKind::Placeholder(_)
@@ -1082,3 +1076,24 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
         ControlFlow::CONTINUE
     }
 }
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        ty::Unevaluated {
+            def: self.def,
+            substs_: Some(self.substs(folder.tcx()).fold_with(folder)),
+            promoted: self.promoted,
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        if let Some(tcx) = visitor.tcx_for_anon_const_substs() {
+            self.substs(tcx).visit_with(visitor)
+        } else if let Some(substs) = self.substs_ {
+            substs.visit_with(visitor)
+        } else {
+            debug!("ignoring default substs of `{:?}`", self.def);
+            ControlFlow::CONTINUE
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index c2fe5f1ef3f..c9fc97f0aaf 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -196,7 +196,8 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
                 | ty::ConstKind::Error(_) => {}
 
                 ty::ConstKind::Unevaluated(ct) => {
-                    stack.extend(ct.substs.iter().rev());
+                    // TODO
+                    stack.extend(ct.substs_.unwrap().iter().rev());
                 }
             }
         }
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
index 999b25319bf..639bcb8fa94 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -377,8 +377,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
                 },
                 _ => None,
             };
-            if let Some(ty::Unevaluated { def, substs, promoted }) = maybe_uneval {
-                if let Some(promoted) = promoted {
+            if let Some(uv) = maybe_uneval {
+                if let Some(promoted) = uv.promoted {
                     let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
                                      promoted: &Body<'tcx>,
                                      ty,
@@ -413,8 +413,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
                         ConstraintCategory::Boring,
                         self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
                             constant.literal.ty(),
-                            def.did,
-                            UserSubsts { substs, user_self_ty: None },
+                            uv.def.did,
+                            UserSubsts { substs: uv.substs(self.tcx()), user_self_ty: None },
                         )),
                     ) {
                         span_mirbug!(
diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs
index 81f78621d14..403dc1b4793 100644
--- a/compiler/rustc_mir/src/interpret/operand.rs
+++ b/compiler/rustc_mir/src/interpret/operand.rs
@@ -555,9 +555,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         match val.val {
             ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric),
             ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)),
-            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
-                let instance = self.resolve(def, substs)?;
-                Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into())
+            ty::ConstKind::Unevaluated(uv) => {
+                let instance = self.resolve(uv.def, uv.substs(*self.tcx))?;
+                Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into())
             }
             ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => {
                 span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val)
diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs
index b7ab2e88b96..b9d6e002e2d 100644
--- a/compiler/rustc_mir/src/interpret/util.rs
+++ b/compiler/rustc_mir/src/interpret/util.rs
@@ -21,8 +21,8 @@ where
     impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
         type BreakTy = FoundParam;
 
-        fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-            self.tcx
+        fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+            Some(self.tcx)
         }
 
         fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs
index dd7500e9e9d..b086053a0c1 100644
--- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs
+++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs
@@ -283,8 +283,8 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        self.tcx
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        Some(self.tcx)
     }
     #[instrument(skip(self))]
     fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -298,7 +298,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
                 self.unused_parameters.clear(param.index);
                 ControlFlow::CONTINUE
             }
-            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted: Some(p)})
+            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted: Some(p)})
                 // Avoid considering `T` unused when constants are of the form:
                 //   `<Self as Foo<T>>::foo::promoted[p]`
                 if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self =>
@@ -309,10 +309,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
                 self.visit_body(&promoted[p]);
                 ControlFlow::CONTINUE
             }
-            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None })
-                if self.tcx.def_kind(def.did) == DefKind::AnonConst =>
+            ty::ConstKind::Unevaluated(uv)
+                if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst =>
             {
-                self.visit_child_body(def.did, substs);
+                self.visit_child_body(uv.def.did, uv.substs(self.tcx));
                 ControlFlow::CONTINUE
             }
             _ => c.super_visit_with(self),
@@ -357,8 +357,8 @@ struct HasUsedGenericParams<'a, 'tcx> {
 impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> {
     type BreakTy = ();
 
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        self.tcx
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        Some(self.tcx)
     }
 
     #[instrument(skip(self))]
diff --git a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
index ac8c748ea85..413a9638eb3 100644
--- a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
@@ -247,7 +247,7 @@ where
 
     // Check the qualifs of the value of `const` items.
     if let Some(ct) = constant.literal.const_for_ty() {
-        if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) = ct.val {
+        if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) = ct.val {
             assert!(promoted.is_none());
             // Don't peek inside trait associated constants.
             if cx.tcx.trait_of_item(def.did).is_none() {
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs
index 4578f04c034..98581f76821 100644
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ b/compiler/rustc_mir/src/transform/const_prop.rs
@@ -483,7 +483,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                             // Promoteds must lint and not error as the user didn't ask for them
                             ConstKind::Unevaluated(ty::Unevaluated {
                                 def: _,
-                                substs: _,
+                                substs_: _,
                                 promoted: Some(_),
                             }) => true,
                             // Out of backwards compatibility we cannot report hard errors in unused
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index 822b422985c..14c9b3b0d47 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -859,13 +859,17 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                             ty,
                             val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                                 def,
-                                substs: InternalSubsts::for_item(tcx, def.did, |param, _| {
-                                    if let ty::GenericParamDefKind::Lifetime = param.kind {
-                                        tcx.lifetimes.re_erased.into()
-                                    } else {
-                                        tcx.mk_param_from_def(param)
-                                    }
-                                }),
+                                substs_: Some(InternalSubsts::for_item(
+                                    tcx,
+                                    def.did,
+                                    |param, _| {
+                                        if let ty::GenericParamDefKind::Lifetime = param.kind {
+                                            tcx.lifetimes.re_erased.into()
+                                        } else {
+                                            tcx.mk_param_from_def(param)
+                                        }
+                                    },
+                                )),
                                 promoted: Some(promoted_id),
                             }),
                         })
diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs
index 435fca4a11b..92591db668c 100644
--- a/compiler/rustc_mir/src/util/pretty.rs
+++ b/compiler/rustc_mir/src/util/pretty.rs
@@ -475,7 +475,7 @@ impl Visitor<'tcx> for ExtraComments<'tcx> {
                 ty::ConstKind::Unevaluated(uv) => format!(
                     "Unevaluated({}, {:?}, {:?})",
                     self.tcx.def_path_str(uv.def.did),
-                    uv.substs,
+                    uv.substs(self.tcx),
                     uv.promoted
                 ),
                 ty::ConstKind::Value(val) => format!("Value({:?})", val),
@@ -682,8 +682,10 @@ pub fn write_allocations<'tcx>(
     }
     struct CollectAllocIds(BTreeSet<AllocId>);
     impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds {
-        fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-            bug!("tcx_for_anon_const_substs called for CollectAllocIds")
+        fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+            // `AllocId`s are only inside of `ConstKind::Value` which
+            // can't be part of the anon const default substs.
+            None
         }
 
         fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index f1d882e1ddd..9106f1d2342 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -693,11 +693,10 @@ impl<'tcx> Cx<'tcx> {
                                 // and not the beginning of discriminants (which is always `0`)
                                 let substs = InternalSubsts::identity_for_item(self.tcx(), did);
                                 let lhs = ty::Const {
-                                    val: ty::ConstKind::Unevaluated(ty::Unevaluated {
-                                        def: ty::WithOptConstParam::unknown(did),
+                                    val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(
+                                        ty::WithOptConstParam::unknown(did),
                                         substs,
-                                        promoted: None,
-                                    }),
+                                    )),
                                     ty: var_ty,
                                 };
                                 let lhs = self.thir.exprs.push(mk_const(self.tcx().mk_const(lhs)));
@@ -889,11 +888,10 @@ impl<'tcx> Cx<'tcx> {
                 debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
                 ExprKind::Literal {
                     literal: self.tcx.mk_const(ty::Const {
-                        val: ty::ConstKind::Unevaluated(ty::Unevaluated {
-                            def: ty::WithOptConstParam::unknown(def_id),
+                        val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(
+                            ty::WithOptConstParam::unknown(def_id),
                             substs,
-                            promoted: None,
-                        }),
+                        )),
                         ty: self.typeck_results().node_type(expr.hir_id),
                     }),
                     user_ty,
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 45d31068668..fb223d8fa75 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -179,8 +179,8 @@ where
 {
     type BreakTy = V::BreakTy;
 
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        self.def_id_visitor.tcx()
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        Some(self.def_id_visitor.tcx())
     }
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 083a962ac7b..f89ca0fed03 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -558,8 +558,8 @@ impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
 where
     OP: FnMut(ty::Region<'tcx>),
 {
-    fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> {
-        self.tcx
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        Some(self.tcx)
     }
 
     fn visit_binder<T: TypeFoldable<'tcx>>(
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index b1a938836b7..2f1e7e9d509 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -155,11 +155,8 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
     // and hopefully soon change this to an error.
     //
     // See #74595 for more details about this.
-    let concrete = infcx.const_eval_resolve(
-        param_env,
-        ty::Unevaluated { def, substs, promoted: None },
-        Some(span),
-    );
+    let concrete =
+        infcx.const_eval_resolve(param_env, ty::Unevaluated::new(def, substs), Some(span));
 
     if concrete.is_ok() && substs.has_param_types_or_consts() {
         match infcx.tcx.def_kind(def.did) {
@@ -217,9 +214,7 @@ impl AbstractConst<'tcx> {
         ct: &ty::Const<'tcx>,
     ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
         match ct.val {
-            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: _ }) => {
-                AbstractConst::new(tcx, def, substs)
-            }
+            ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.def, uv.substs(tcx)),
             ty::ConstKind::Error(_) => Err(ErrorReported),
             _ => Ok(None),
         }
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 4b94deff825..903912c3361 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -570,7 +570,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
 
                 ty::PredicateKind::ConstEquate(c1, c2) => {
                     debug!(?c1, ?c2, "equating consts");
-                    if self.selcx.tcx().features().const_evaluatable_checked {
+                    let tcx = self.selcx.tcx();
+                    if tcx.features().const_evaluatable_checked {
                         // FIXME: we probably should only try to unify abstract constants
                         // if the constants depend on generic parameters.
                         //
@@ -597,7 +598,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                                 Err(ErrorHandled::TooGeneric) => {
                                     stalled_on.extend(
                                         unevaluated
-                                            .substs
+                                            .substs(tcx)
                                             .iter()
                                             .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
                                     );
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index b81ca52f9fd..01bad14c8fa 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -771,8 +771,8 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
 
     impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> {
         type BreakTy = ();
-        fn tcx_for_anon_const_substs<'a>(&'a self) -> TyCtxt<'tcx> {
-            self.tcx
+        fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+            Some(self.tcx)
         }
 
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index fd7dc55ac84..ac8bab0cf36 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -130,8 +130,8 @@ impl Search<'a, 'tcx> {
 
 impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
     type BreakTy = NonStructuralMatchTy<'tcx>;
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        self.tcx()
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        Some(self.tcx())
     }
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index afef784b4c6..e4457606132 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -435,13 +435,14 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 
                 GenericArgKind::Const(constant) => {
                     match constant.val {
-                        ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
-                            assert!(promoted.is_none());
+                        ty::ConstKind::Unevaluated(uv) => {
+                            assert!(uv.promoted.is_none());
+                            let substs = uv.substs(self.tcx());
 
-                            let obligations = self.nominal_obligations(def.did, substs);
+                            let obligations = self.nominal_obligations(uv.def.did, substs);
                             self.out.extend(obligations);
 
-                            let predicate = ty::PredicateKind::ConstEvaluatable(def, substs)
+                            let predicate = ty::PredicateKind::ConstEvaluatable(uv.def, substs)
                                 .to_predicate(self.tcx());
                             let cause = self.cause(traits::MiscObligation);
                             self.out.push(traits::Obligation::with_depth(
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index d07eeaedd82..1d4196e5747 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -854,8 +854,8 @@ impl<'tcx> BoundVarsCollector<'tcx> {
 }
 
 impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        self.tcx
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        Some(self.tcx)
     }
 
     fn visit_binder<T: TypeFoldable<'tcx>>(
@@ -1076,8 +1076,9 @@ impl PlaceholdersCollector {
 }
 
 impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        bug!("tcx_for_anon_const_substs called for PlaceholdersCollector");
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        // Anon const substs do not contain placeholders by default.
+        None
     }
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index b9fbb5da3e6..b00d2ab3561 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -54,8 +54,9 @@ impl<'tcx> BoundVarsCollector<'tcx> {
 impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
     type BreakTy = ();
 
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        bug!("default anon const substs can't be bound vars");
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        // Anon const substs do not contain bound vars by default.
+        None
     }
     fn visit_binder<T: TypeFoldable<'tcx>>(
         &mut self,
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 06fae26f7df..649574fe195 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -473,8 +473,8 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
     struct FindParentLifetimeVisitor<'tcx>(TyCtxt<'tcx>, &'tcx ty::Generics);
     impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
         type BreakTy = FoundParentLifetime;
-        fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-            self.0
+        fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+            Some(self.0)
         }
 
         fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -510,8 +510,8 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
 
     impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
         type BreakTy = Ty<'tcx>;
-        fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-            self.tcx
+        fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+            Some(self.tcx)
         }
 
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -1584,10 +1584,11 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
                 .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
                 .filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
             {
-                struct VisitTypes(Vec<DefId>);
-                impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes {
-                    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-                        bug!("tcx_for_anon_const_substs called for VisitTypes");
+                struct OpaqueTypeCollector(Vec<DefId>);
+                impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypeCollector {
+                    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+                        // Default anon const substs cannot contain opaque types.
+                        None
                     }
                     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                         match *t.kind() {
@@ -1599,7 +1600,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
                         }
                     }
                 }
-                let mut visitor = VisitTypes(vec![]);
+                let mut visitor = OpaqueTypeCollector(vec![]);
                 ty.visit_with(&mut visitor);
                 for def_id in visitor.0 {
                     let ty_span = tcx.def_span(def_id);
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 3503d68e8f0..9b495fba197 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -1006,8 +1006,8 @@ fn suggest_constraining_param(
 struct TypeParamVisitor<'tcx>(TyCtxt<'tcx>, Vec<Ty<'tcx>>);
 
 impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        self.0
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        Some(self.0)
     }
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if let ty::Param(_) = ty.kind() {
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 44caf348a98..0d121b9da87 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -831,8 +831,8 @@ fn check_where_clauses<'tcx, 'fcx>(
             }
             impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams<'tcx> {
                 type BreakTy = ();
-                fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-                    self.tcx
+                fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+                    Some(self.tcx)
                 }
 
                 fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index d5316352c54..a5a402bc26a 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -68,6 +68,7 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
         opt_const_param_of: type_of::opt_const_param_of,
+        default_anon_const_substs: type_of::default_anon_const_substs,
         type_of: type_of::type_of,
         item_bounds: item_bounds::item_bounds,
         explicit_item_bounds: item_bounds::explicit_item_bounds,
@@ -2355,7 +2356,8 @@ fn const_evaluatable_predicates_of<'tcx>(
                 assert_eq!(uv.promoted, None);
                 let span = self.tcx.hir().span(c.hir_id);
                 self.preds.insert((
-                    ty::PredicateKind::ConstEvaluatable(uv.def, uv.substs).to_predicate(self.tcx),
+                    ty::PredicateKind::ConstEvaluatable(uv.def, uv.substs(self.tcx))
+                        .to_predicate(self.tcx),
                     span,
                 ));
             }
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 4048a54b58c..98f5f73b7be 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -7,7 +7,7 @@ use rustc_hir::intravisit;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{HirId, Node};
 use rustc_middle::hir::map::Map;
-use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
+use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, SubstsRef};
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
 use rustc_span::symbol::Ident;
@@ -274,6 +274,10 @@ fn get_path_containing_arg_in_pat<'hir>(
     arg_path
 }
 
+pub(super) fn default_anon_const_substs(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> {
+    InternalSubsts::identity_for_item(tcx, def_id)
+}
+
 pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
     let def_id = def_id.expect_local();
     use rustc_hir::*;
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs
index 140348ea4ec..9b6f0be47ca 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_typeck/src/constrained_generic_params.rs
@@ -60,8 +60,8 @@ struct ParameterCollector<'tcx> {
 }
 
 impl<'tcx> TypeVisitor<'tcx> for ParameterCollector<'tcx> {
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        self.tcx
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        Some(self.tcx)
     }
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index bdd5350aab2..bdfe3ffc13f 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -287,7 +287,7 @@ crate fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
 
 crate fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String {
     match n.val {
-        ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) => {
+        ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) => {
             let mut s = if let Some(def) = def.as_local() {
                 let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def.did);
                 print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(hir_id))
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 3f9110295fc..2a85a67fa09 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -187,11 +187,7 @@ fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: D
 
     let result = cx.tcx.const_eval_resolve(
         cx.param_env,
-        ty::Unevaluated {
-            def: ty::WithOptConstParam::unknown(def_id),
-            substs,
-            promoted: None,
-        },
+        ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs),
         None,
     );
     is_value_unfrozen_raw(cx, result, ty)
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index 2335d2248aa..f5e43264a5c 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -705,8 +705,8 @@ struct ContainsRegion<'tcx>(TyCtxt<'tcx>);
 
 impl<'tcx> TypeVisitor<'tcx> for ContainsRegion<'tcx> {
     type BreakTy = ();
-    fn tcx_for_anon_const_substs(&self) -> TyCtxt<'tcx> {
-        self.0
+    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+        Some(self.0)
     }
 
     fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 9ba1381da65..8bf31807d55 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -346,11 +346,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                     .tcx
                     .const_eval_resolve(
                         self.param_env,
-                        ty::Unevaluated {
-                            def: ty::WithOptConstParam::unknown(def_id),
-                            substs,
-                            promoted: None,
-                        },
+                        ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs),
                         None,
                     )
                     .ok()