about summary refs log tree commit diff
path: root/compiler/rustc_const_eval/src
diff options
context:
space:
mode:
authorlcnr <rust@lcnr.de>2024-11-15 13:53:31 +0100
committerlcnr <rust@lcnr.de>2024-11-18 10:38:56 +0100
commit9cba14b95bb07a5b31ed1aac2bf4eadd248232da (patch)
tree60791c9abdfdc19133ab67c41a6d2872dfce745b /compiler/rustc_const_eval/src
parentbf6adec108e83c5ddfcbb443a9177203db5eb945 (diff)
downloadrust-9cba14b95bb07a5b31ed1aac2bf4eadd248232da.tar.gz
rust-9cba14b95bb07a5b31ed1aac2bf4eadd248232da.zip
use `TypingEnv` when no `infcx` is available
the behavior of the type system not only depends on the current
assumptions, but also the currentnphase of the compiler. This is
mostly necessary as we need to decide whether and how to reveal
opaque types. We track this via the `TypingMode`.
Diffstat (limited to 'compiler/rustc_const_eval/src')
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs11
-rw-r--r--compiler/rustc_const_eval/src/check_consts/mod.rs8
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs8
-rw-r--r--compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs8
-rw-r--r--compiler/rustc_const_eval/src/check_consts/qualifs.rs24
-rw-r--r--compiler/rustc_const_eval/src/check_consts/resolver.rs5
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs6
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs3
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs11
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs58
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs52
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs9
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs21
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/stack.rs15
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs6
-rw-r--r--compiler/rustc_const_eval/src/lib.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/alignment.rs6
-rw-r--r--compiler/rustc_const_eval/src/util/check_validity_requirement.rs10
-rw-r--r--compiler/rustc_const_eval/src/util/compare_types.rs13
24 files changed, 145 insertions, 154 deletions
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index ffe32acb316..50e8a168eeb 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -388,7 +388,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
             return false;
         }
 
-        let infcx = tcx.infer_ctxt().build(self.body.typing_mode(tcx));
+        let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(self.body.typing_env(tcx));
         let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
         let body_id = self.body.source.def_id().expect_local();
@@ -398,11 +398,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
                 ty::BoundConstness::Const
             }
         };
-        let const_conditions = ocx.normalize(
-            &ObligationCause::misc(call_span, body_id),
-            self.param_env,
-            const_conditions,
-        );
+        let const_conditions =
+            ocx.normalize(&ObligationCause::misc(call_span, body_id), param_env, const_conditions);
         ocx.register_obligations(const_conditions.into_iter().map(|(trait_ref, span)| {
             Obligation::new(
                 tcx,
@@ -411,7 +408,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
                     body_id,
                     ObligationCauseCode::WhereClause(callee, span),
                 ),
-                self.param_env,
+                param_env,
                 trait_ref.to_host_effect_clause(tcx, host_polarity),
             )
         }));
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index ebdd55a4f70..80d3c6448aa 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -24,17 +24,15 @@ mod resolver;
 pub struct ConstCx<'mir, 'tcx> {
     pub body: &'mir mir::Body<'tcx>,
     pub tcx: TyCtxt<'tcx>,
-    pub param_env: ty::ParamEnv<'tcx>,
+    pub typing_env: ty::TypingEnv<'tcx>,
     pub const_kind: Option<hir::ConstContext>,
 }
 
 impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self {
-        let def_id = body.source.def_id().expect_local();
-        let param_env = tcx.param_env(def_id);
-
+        let typing_env = body.typing_env(tcx);
         let const_kind = tcx.hir().body_const_context(body.source.def_id().expect_local());
-        ConstCx { body, tcx, param_env, const_kind }
+        ConstCx { body, tcx, typing_env, const_kind }
     }
 
     pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> {
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index ca95e42dd2b..8ba6b89aad4 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -120,7 +120,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
     #[allow(rustc::untranslatable_diagnostic)]
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
         let FnCallNonConst { callee, args, span, call_source } = *self;
-        let ConstCx { tcx, param_env, .. } = *ccx;
+        let ConstCx { tcx, typing_env, .. } = *ccx;
         let caller = ccx.def_id();
 
         let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
@@ -146,13 +146,11 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                     }
                 }
                 ty::Adt(..) => {
+                    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
                     let obligation =
                         Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
-
-                    let infcx = tcx.infer_ctxt().build(ccx.body.typing_mode(tcx));
                     let mut selcx = SelectionContext::new(&infcx);
                     let implsrc = selcx.select(&obligation);
-
                     if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
                         // FIXME(const_trait_impl) revisit this
                         if !tcx.is_const_trait_impl(data.impl_def_id) {
@@ -166,7 +164,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
         };
 
         let call_kind =
-            call_kind(tcx, ccx.param_env, callee, args, span, call_source.from_hir_call(), None);
+            call_kind(tcx, ccx.typing_env, callee, args, span, call_source.from_hir_call(), None);
 
         debug!(?call_kind);
 
diff --git a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
index 0173a528c22..f6eb130fbd3 100644
--- a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
@@ -32,17 +32,15 @@ pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool {
 /// This is separate from the rest of the const checking logic because it must run after drop
 /// elaboration.
 pub fn check_live_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
-    let def_id = body.source.def_id().expect_local();
-    let const_kind = tcx.hir().body_const_context(def_id);
-    if const_kind.is_none() {
+    let ccx = ConstCx::new(tcx, body);
+    if ccx.const_kind.is_none() {
         return;
     }
 
-    if tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
+    if tcx.has_attr(body.source.def_id(), sym::rustc_do_not_const_check) {
         return;
     }
 
-    let ccx = ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def_id) };
     if !checking_enabled(&ccx) {
         return;
     }
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index 29a08579175..bc416acc58d 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -106,20 +106,24 @@ impl Qualif for HasMutInterior {
         // Instead we invoke an obligation context manually, and provide the opaque type inference settings
         // that allow the trait solver to just error out instead of cycling.
         let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, Some(cx.body.span));
-
+        // FIXME(#132279): Once we've got a typing mode which reveals opaque types using the HIR
+        // typeck results without causing query cycles, we should use this here instead of defining
+        // opaque types.
+        let typing_env = ty::TypingEnv {
+            typing_mode: ty::TypingMode::analysis_in_body(
+                cx.tcx,
+                cx.body.source.def_id().expect_local(),
+            ),
+            param_env: cx.typing_env.param_env,
+        };
+        let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(typing_env);
+        let ocx = ObligationCtxt::new(&infcx);
         let obligation = Obligation::new(
             cx.tcx,
             ObligationCause::dummy_with_span(cx.body.span),
-            cx.param_env,
+            param_env,
             ty::TraitRef::new(cx.tcx, freeze_def_id, [ty::GenericArg::from(ty)]),
         );
-
-        // FIXME(#132279): This should eventually use the already defined hidden types.
-        let infcx = cx.tcx.infer_ctxt().build(ty::TypingMode::analysis_in_body(
-            cx.tcx,
-            cx.body.source.def_id().expect_local(),
-        ));
-        let ocx = ObligationCtxt::new(&infcx);
         ocx.register_obligation(obligation);
         let errors = ocx.select_all_or_error();
         !errors.is_empty()
@@ -156,7 +160,7 @@ impl Qualif for NeedsDrop {
     }
 
     fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
-        ty.needs_drop(cx.tcx, cx.param_env)
+        ty.needs_drop(cx.tcx, cx.typing_env)
     }
 
     fn in_adt_inherently<'tcx>(
diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs
index 74eb6b37fbb..03624a2ce50 100644
--- a/compiler/rustc_const_eval/src/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs
@@ -120,7 +120,10 @@ where
     ///
     /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
     fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
-        !place.ty(self.ccx.body, self.ccx.tcx).ty.is_freeze(self.ccx.tcx, self.ccx.param_env)
+        !place
+            .ty(self.ccx.body, self.ccx.tcx)
+            .ty
+            .is_freeze(self.ccx.tcx, self.ccx.typing_env.param_env)
     }
 }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index a430d9dc797..ca3ee6773a0 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -221,7 +221,7 @@ pub(super) fn op_to_const<'tcx>(
                 let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs
                 debug_assert!(
                     matches!(
-                        ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.param_env).kind(),
+                        ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env()).kind(),
                         ty::Str | ty::Slice(..),
                     ),
                     "`ConstValue::Slice` is for slice-tailed types only, but got {}",
@@ -280,11 +280,13 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
     // opaque types. This is needed for trivial things like `size_of`, but also for using associated
     // types that are not specified in the opaque type.
     assert_eq!(key.param_env.reveal(), Reveal::All);
+    let typing_env =
+        ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: key.param_env };
 
     // We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
     // Catch such calls and evaluate them instead of trying to load a constant's MIR.
     if let ty::InstanceKind::Intrinsic(def_id) = key.value.instance.def {
-        let ty = key.value.instance.ty(tcx, key.param_env);
+        let ty = key.value.instance.ty(tcx, typing_env);
         let ty::FnDef(_, args) = ty.kind() else {
             bug!("intrinsic with type {:?}", ty);
         };
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index f12320cb851..19c3195aaa4 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -249,9 +249,10 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
         } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) {
             // For panic_fmt, call const_panic_fmt instead.
             let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None);
+            // FIXME(@lcnr): why does this use an empty env if we've got a `param_env` right here.
             let new_instance = ty::Instance::expect_resolve(
                 *self.tcx,
-                ty::ParamEnv::reveal_all(),
+                ty::TypingEnv::fully_monomorphized(),
                 const_def_id,
                 instance.args,
                 self.cur_span(),
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index ea88b2ed22e..64bedea3b3f 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -2,6 +2,7 @@ use rustc_abi::{BackendRepr, VariantIdx};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
 use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
+use rustc_middle::ty::solve::Reveal;
 use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_span::DUMMY_SP;
@@ -281,8 +282,9 @@ pub fn valtree_to_const_value<'tcx>(
     // the `ValTree` and using `place_projection` and `place_field` to
     // create inner `MPlace`s which are filled recursively.
     // FIXME Does this need an example?
-
     let (param_env, ty) = param_env_ty.into_parts();
+    debug_assert_eq!(param_env.reveal(), Reveal::All);
+    let typing_env = ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env };
 
     match *ty.kind() {
         ty::FnDef(..) => {
@@ -302,11 +304,12 @@ pub fn valtree_to_const_value<'tcx>(
             let mut ecx =
                 mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No);
             let imm = valtree_to_ref(&mut ecx, valtree, inner_ty);
-            let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap());
+            let imm =
+                ImmTy::from_immediate(imm, tcx.layout_of(typing_env.as_query_input(ty)).unwrap());
             op_to_const(&ecx, &imm.into(), /* for diagnostics */ false)
         }
         ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
-            let layout = tcx.layout_of(param_env_ty).unwrap();
+            let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap();
             if layout.is_zst() {
                 // Fast path to avoid some allocations.
                 return mir::ConstValue::ZeroSized;
@@ -319,7 +322,7 @@ pub fn valtree_to_const_value<'tcx>(
                 let branches = valtree.unwrap_branch();
                 // Find the non-ZST field. (There can be aligned ZST!)
                 for (i, &inner_valtree) in branches.iter().enumerate() {
-                    let field = layout.field(&LayoutCx::new(tcx, param_env), i);
+                    let field = layout.field(&LayoutCx::new(tcx, typing_env), i);
                     if !field.is_zst() {
                         return valtree_to_const_value(tcx, param_env.and(field.ty), inner_valtree);
                     }
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index ef0902e4226..6cfe4b21907 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -215,7 +215,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 // Even if `ty` is normalized, the search for the unsized tail will project
                 // to fields, which can yield non-normalized types. So we need to provide a
                 // normalization function.
-                let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty);
+                let normalize = |ty| self.tcx.normalize_erasing_regions(self.typing_env(), ty);
                 ty.ptr_metadata_ty(*self.tcx, normalize)
             };
             return interp_ok(meta_ty(caller) == meta_ty(callee));
@@ -652,35 +652,35 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 };
 
                 // Obtain the underlying trait we are working on, and the adjusted receiver argument.
-                let (trait_, dyn_ty, adjusted_recv) = if let ty::Dynamic(data, _, ty::DynStar) =
-                    receiver_place.layout.ty.kind()
-                {
-                    let recv = self.unpack_dyn_star(&receiver_place, data)?;
+                let (trait_, dyn_ty, adjusted_recv) =
+                    if let ty::Dynamic(data, _, ty::DynStar) = receiver_place.layout.ty.kind() {
+                        let recv = self.unpack_dyn_star(&receiver_place, data)?;
 
-                    (data.principal(), recv.layout.ty, recv.ptr())
-                } else {
-                    // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
-                    // (For that reason we also cannot use `unpack_dyn_trait`.)
-                    let receiver_tail =
-                        self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.param_env);
-                    let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
-                        span_bug!(
-                            self.cur_span(),
-                            "dynamic call on non-`dyn` type {}",
-                            receiver_tail
-                        )
+                        (data.principal(), recv.layout.ty, recv.ptr())
+                    } else {
+                        // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
+                        // (For that reason we also cannot use `unpack_dyn_trait`.)
+                        let receiver_tail = self
+                            .tcx
+                            .struct_tail_for_codegen(receiver_place.layout.ty, self.typing_env());
+                        let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
+                            span_bug!(
+                                self.cur_span(),
+                                "dynamic call on non-`dyn` type {}",
+                                receiver_tail
+                            )
+                        };
+                        assert!(receiver_place.layout.is_unsized());
+
+                        // Get the required information from the vtable.
+                        let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?;
+                        let dyn_ty = self.get_ptr_vtable_ty(vptr, Some(receiver_trait))?;
+
+                        // It might be surprising that we use a pointer as the receiver even if this
+                        // is a by-val case; this works because by-val passing of an unsized `dyn
+                        // Trait` to a function is actually desugared to a pointer.
+                        (receiver_trait.principal(), dyn_ty, receiver_place.ptr())
                     };
-                    assert!(receiver_place.layout.is_unsized());
-
-                    // Get the required information from the vtable.
-                    let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?;
-                    let dyn_ty = self.get_ptr_vtable_ty(vptr, Some(receiver_trait))?;
-
-                    // It might be surprising that we use a pointer as the receiver even if this
-                    // is a by-val case; this works because by-val passing of an unsized `dyn
-                    // Trait` to a function is actually desugared to a pointer.
-                    (receiver_trait.principal(), dyn_ty, receiver_place.ptr())
-                };
 
                 // Now determine the actual method to call. Usually we use the easy way of just
                 // looking up the method at index `idx`.
@@ -704,7 +704,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
                     let concrete_method = Instance::expect_resolve_for_vtable(
                         tcx,
-                        self.param_env,
+                        self.typing_env(),
                         def_id,
                         instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args),
                         self.cur_span(),
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 49559059265..2d1bb5c9551 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -83,7 +83,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     ty::FnDef(def_id, args) => {
                         let instance = ty::Instance::resolve_for_fn_ptr(
                             *self.tcx,
-                            self.param_env,
+                            self.typing_env(),
                             def_id,
                             args,
                         )
@@ -384,7 +384,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx> {
         // A<Struct> -> A<Trait> conversion
         let (src_pointee_ty, dest_pointee_ty) =
-            self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.param_env);
+            self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.typing_env());
 
         match (src_pointee_ty.kind(), dest_pointee_ty.kind()) {
             (&ty::Array(_, length), &ty::Slice(_)) => {
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index ff6d5b28b3b..70a696e3e3e 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -10,9 +10,7 @@ use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{
     self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
 };
-use rustc_middle::ty::{
-    self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypingMode, Variance,
-};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance};
 use rustc_middle::{mir, span_bug};
 use rustc_session::Limit;
 use rustc_span::Span;
@@ -65,12 +63,12 @@ where
     }
 }
 
-impl<'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'tcx, M>
+impl<'tcx, M> layout::HasTypingEnv<'tcx> for InterpCx<'tcx, M>
 where
     M: Machine<'tcx>,
 {
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.typing_env()
     }
 }
 
@@ -116,8 +114,7 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> {
 /// This test should be symmetric, as it is primarily about layout compatibility.
 pub(super) fn mir_assign_valid_types<'tcx>(
     tcx: TyCtxt<'tcx>,
-    typing_mode: TypingMode<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: TypingEnv<'tcx>,
     src: TyAndLayout<'tcx>,
     dest: TyAndLayout<'tcx>,
 ) -> bool {
@@ -125,7 +122,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
     // all normal lifetimes are erased, higher-ranked types with their
     // late-bound lifetimes are still around and can lead to type
     // differences.
-    if util::relate_types(tcx, typing_mode, param_env, Variance::Covariant, src.ty, dest.ty) {
+    if util::relate_types(tcx, typing_env, Variance::Covariant, src.ty, dest.ty) {
         // Make sure the layout is equal, too -- just to be safe. Miri really
         // needs layout equality. For performance reason we skip this check when
         // the types are equal. Equal types *can* have different layouts when
@@ -145,8 +142,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
 #[cfg_attr(not(debug_assertions), inline(always))]
 pub(super) fn from_known_layout<'tcx>(
     tcx: TyCtxtAt<'tcx>,
-    typing_mode: TypingMode<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: TypingEnv<'tcx>,
     known_layout: Option<TyAndLayout<'tcx>>,
     compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>,
 ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
@@ -155,13 +151,7 @@ pub(super) fn from_known_layout<'tcx>(
         Some(known_layout) => {
             if cfg!(debug_assertions) {
                 let check_layout = compute()?;
-                if !mir_assign_valid_types(
-                    tcx.tcx,
-                    typing_mode,
-                    param_env,
-                    check_layout,
-                    known_layout,
-                ) {
+                if !mir_assign_valid_types(tcx.tcx, typing_env, check_layout, known_layout) {
                     span_bug!(
                         tcx.span,
                         "expected type differs from actual type.\nexpected: {}\nactual: {}",
@@ -211,9 +201,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         }
     }
 
-    pub fn typing_mode(&self) -> TypingMode<'tcx> {
+    /// During CTFE we're always in `PostAnalysis` mode.
+    #[inline(always)]
+    pub fn typing_env(&self) -> ty::TypingEnv<'tcx> {
         debug_assert_eq!(self.param_env.reveal(), Reveal::All);
-        TypingMode::PostAnalysis
+        ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: self.param_env }
     }
 
     /// Returns the span of the currently executed statement/terminator.
@@ -304,13 +296,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             .instance
             .try_instantiate_mir_and_normalize_erasing_regions(
                 *self.tcx,
-                self.param_env,
+                self.typing_env(),
                 ty::EarlyBinder::bind(value),
             )
             .map_err(|_| ErrorHandled::TooGeneric(self.cur_span()))
     }
 
-    /// The `args` are assumed to already be in our interpreter "universe" (param_env).
+    /// The `args` are assumed to already be in our interpreter "universe".
     pub(super) fn resolve(
         &self,
         def: DefId,
@@ -319,7 +311,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         trace!("resolve: {:?}, {:#?}", def, args);
         trace!("param_env: {:#?}", self.param_env);
         trace!("args: {:#?}", args);
-        match ty::Instance::try_resolve(*self.tcx, self.param_env, def, args) {
+        match ty::Instance::try_resolve(*self.tcx, self.typing_env(), def, args) {
             Ok(Some(instance)) => interp_ok(instance),
             Ok(None) => throw_inval!(TooGeneric),
 
@@ -328,7 +320,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         }
     }
 
-    /// Check if the two things are equal in the current param_env, using an infctx to get proper
+    /// Check if the two things are equal in the current param_env, using an infcx to get proper
     /// equality checks.
     #[instrument(level = "trace", skip(self), ret)]
     pub(super) fn eq_in_param_env<T>(&self, a: T, b: T) -> bool
@@ -340,14 +332,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             return true;
         }
         // Slow path: spin up an inference context to check if these traits are sufficiently equal.
-        let infcx = self.tcx.infer_ctxt().build(self.typing_mode());
+        let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env());
         let ocx = ObligationCtxt::new(&infcx);
         let cause = ObligationCause::dummy_with_span(self.cur_span());
         // equate the two trait refs after normalization
-        let a = ocx.normalize(&cause, self.param_env, a);
-        let b = ocx.normalize(&cause, self.param_env, b);
+        let a = ocx.normalize(&cause, param_env, a);
+        let b = ocx.normalize(&cause, param_env, b);
 
-        if let Err(terr) = ocx.eq(&cause, self.param_env, a, b) {
+        if let Err(terr) = ocx.eq(&cause, param_env, a, b) {
             trace!(?terr);
             return false;
         }
@@ -572,7 +564,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let val = if self.tcx.is_static(gid.instance.def_id()) {
             let alloc_id = self.tcx.reserve_and_set_static_alloc(gid.instance.def_id());
 
-            let ty = instance.ty(self.tcx.tcx, self.param_env);
+            let ty = instance.ty(self.tcx.tcx, self.typing_env());
             mir::ConstAlloc { alloc_id, ty }
         } else {
             self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(self.param_env.and(gid)))?
@@ -587,7 +579,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| {
-            let const_val = val.eval(*ecx.tcx, ecx.param_env, span).map_err(|err| {
+            let const_val = val.eval(*ecx.tcx, ecx.typing_env(), span).map_err(|err| {
                 if M::ALL_CONSTS_ARE_PRECHECKED {
                     match err {
                         ErrorHandled::TooGeneric(..) => {},
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index d89d73824aa..fc6a1c4bbc5 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -40,6 +40,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
 ) -> InterpResult<'tcx, ConstValue<'tcx>> {
     let tp_ty = args.type_at(0);
     let name = tcx.item_name(def_id);
+    let typing_env = ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env };
     interp_ok(match name {
         sym::type_name => {
             ensure_monomorphic_enough(tcx, tp_ty)?;
@@ -48,11 +49,13 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
         }
         sym::needs_drop => {
             ensure_monomorphic_enough(tcx, tp_ty)?;
-            ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env))
+            ConstValue::from_bool(tp_ty.needs_drop(tcx, typing_env))
         }
         sym::pref_align_of => {
             // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
-            let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(*e)))?;
+            let layout = tcx
+                .layout_of(typing_env.as_query_input(tp_ty))
+                .map_err(|e| err_inval!(Layout(*e)))?;
             ConstValue::from_target_usize(layout.align.pref.bytes(), &tcx)
         }
         sym::type_id => {
@@ -355,7 +358,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
                 let should_panic = !self
                     .tcx
-                    .check_validity_requirement((requirement, self.param_env.and(ty)))
+                    .check_validity_requirement((requirement, self.typing_env().as_query_input(ty)))
                     .map_err(|_| err_inval!(TooGeneric))?;
 
                 if should_panic {
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 09635c96e57..07566e9fda2 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -859,7 +859,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
         // # Global allocations
         if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) {
-            let (size, align) = global_alloc.size_and_align(*self.tcx, self.param_env);
+            let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env());
             let mutbl = global_alloc.mutability(*self.tcx, self.param_env);
             let kind = match global_alloc {
                 GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData,
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index a130ae89bcb..0157e6c2125 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -8,7 +8,7 @@ use rustc_abi as abi;
 use rustc_abi::{BackendRepr, HasDataLayout, Size};
 use rustc_hir::def::Namespace;
 use rustc_middle::mir::interpret::ScalarSizeMismatch;
-use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
 use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt};
 use rustc_middle::{bug, mir, span_bug, ty};
@@ -297,21 +297,25 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
 
     #[inline]
     pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self {
-        let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(tcx.types.bool)).unwrap();
+        let layout = tcx
+            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tcx.types.bool))
+            .unwrap();
         Self::from_scalar(Scalar::from_bool(b), layout)
     }
 
     #[inline]
     pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self {
         let ty = tcx.ty_ordering_enum(None);
-        let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
+        let layout =
+            tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap();
         Self::from_scalar(Scalar::from_i8(c as i8), layout)
     }
 
     pub fn from_pair(a: Self, b: Self, tcx: TyCtxt<'tcx>) -> Self {
         let layout = tcx
             .layout_of(
-                ty::ParamEnv::reveal_all().and(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])),
+                ty::TypingEnv::fully_monomorphized()
+                    .as_query_input(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])),
             )
             .unwrap();
         Self::from_scalar_pair(a.to_scalar(), b.to_scalar(), layout)
@@ -341,7 +345,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
 
     #[inline]
     #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
-    pub fn to_pair(self, cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>)) -> (Self, Self) {
+    pub fn to_pair(self, cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>)) -> (Self, Self) {
         let layout = self.layout;
         let (val0, val1) = self.to_scalar_pair();
         (
@@ -773,8 +777,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 )?;
             if !mir_assign_valid_types(
                 *self.tcx,
-                self.typing_mode(),
-                self.param_env,
+                self.typing_env(),
                 self.layout_of(normalized_place_ty)?,
                 op.layout,
             ) {
@@ -833,9 +836,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             })
         };
         let layout =
-            from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || {
-                self.layout_of(ty).into()
-            })?;
+            from_known_layout(self.tcx, self.typing_env(), layout, || self.layout_of(ty).into())?;
         let imm = match val_val {
             mir::ConstValue::Indirect { alloc_id, offset } => {
                 // This is const data, no mutation allowed.
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index fbc85d37953..201f1b5dc62 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -533,7 +533,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
             OffsetOf(fields) => {
                 let val =
-                    self.tcx.offset_of_subfield(self.param_env, layout, fields.iter()).bytes();
+                    self.tcx.offset_of_subfield(self.typing_env(), layout, fields.iter()).bytes();
                 ImmTy::from_uint(val, usize_layout())
             }
             UbChecks => ImmTy::from_bool(M::ub_checks(self)?, *self.tcx),
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index cc8d1db6cfb..13fcccca76b 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -540,8 +540,7 @@ where
                 )?;
             if !mir_assign_valid_types(
                 *self.tcx,
-                self.typing_mode(),
-                self.param_env,
+                self.typing_env(),
                 self.layout_of(normalized_place_ty)?,
                 place.layout,
             ) {
@@ -871,13 +870,8 @@ where
     ) -> InterpResult<'tcx> {
         // We do NOT compare the types for equality, because well-typed code can
         // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
-        let layout_compat = mir_assign_valid_types(
-            *self.tcx,
-            self.typing_mode(),
-            self.param_env,
-            src.layout(),
-            dest.layout(),
-        );
+        let layout_compat =
+            mir_assign_valid_types(*self.tcx, self.typing_env(), src.layout(), dest.layout());
         if !allow_transmute && !layout_compat {
             span_bug!(
                 self.cur_span(),
diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs
index 50c0446b3cd..037c1a233ee 100644
--- a/compiler/rustc_const_eval/src/interpret/stack.rs
+++ b/compiler/rustc_const_eval/src/interpret/stack.rs
@@ -379,7 +379,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         for &const_ in body.required_consts() {
             let c =
                 self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
-            c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| {
+            c.eval(*self.tcx, self.typing_env(), const_.span).map_err(|err| {
                 err.emit_note(*self.tcx);
                 err
             })?;
@@ -596,13 +596,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             return interp_ok(layout);
         }
 
-        let layout =
-            from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || {
-                let local_ty = frame.body.local_decls[local].ty;
-                let local_ty =
-                    self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
-                self.layout_of(local_ty).into()
-            })?;
+        let layout = from_known_layout(self.tcx, self.typing_env(), layout, || {
+            let local_ty = frame.body.local_decls[local].ty;
+            let local_ty =
+                self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
+            self.layout_of(local_ty).into()
+        })?;
 
         // Layouts of locals are requested a lot, so we cache them.
         state.layout.set(Some(layout));
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 18cff2c5e0f..d4525243642 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -418,7 +418,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             .collect::<InterpResult<'tcx, Vec<_>>>()?;
 
         let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
-        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
+        let fn_sig =
+            self.tcx.normalize_erasing_late_bound_regions(self.typing_env(), fn_sig_binder);
         let extra_args = &args[fn_sig.inputs().len()..];
         let extra_args =
             self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty));
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 3a68db9f7f7..005b430bc8a 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -448,7 +448,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         meta: MemPlaceMeta<M::Provenance>,
         pointee: TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx> {
-        let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.param_env);
+        let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.typing_env());
         match tail.kind() {
             ty::Dynamic(data, _, ty::Dyn) => {
                 let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
@@ -568,7 +568,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                         throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind });
                     };
                     let (size, _align) =
-                        global_alloc.size_and_align(*self.ecx.tcx, self.ecx.param_env);
+                        global_alloc.size_and_align(*self.ecx.tcx, self.ecx.typing_env());
 
                     if let GlobalAlloc::Static(did) = global_alloc {
                         let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else {
@@ -955,7 +955,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
     ) -> Cow<'e, RangeSet> {
         assert!(layout.ty.is_union());
         assert!(layout.is_sized(), "there are no unsized unions");
-        let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_env);
+        let layout_cx = LayoutCx::new(*ecx.tcx, ecx.typing_env());
         return M::cached_union_data_range(ecx, layout.ty, || {
             let mut out = RangeSet(Vec::new());
             union_data_range_uncached(&layout_cx, layout, Size::ZERO, &mut out);
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 0490195caf4..527236b2c22 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -47,7 +47,7 @@ pub fn provide(providers: &mut Providers) {
     providers.hooks.try_destructure_mir_constant_for_user_output =
         const_eval::try_destructure_mir_constant_for_user_output;
     providers.valtree_to_const_val = |tcx, (ty, valtree)| {
-        const_eval::valtree_to_const_value(tcx, ty::ParamEnv::empty().and(ty), valtree)
+        const_eval::valtree_to_const_value(tcx, ty::ParamEnv::reveal_all().and(ty), valtree)
     };
     providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| {
         util::check_validity_requirement(tcx, init_kind, param_env_and_ty)
diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs
index 6fa7d369229..9507b24f603 100644
--- a/compiler/rustc_const_eval/src/util/alignment.rs
+++ b/compiler/rustc_const_eval/src/util/alignment.rs
@@ -9,7 +9,7 @@ use tracing::debug;
 pub fn is_disaligned<'tcx, L>(
     tcx: TyCtxt<'tcx>,
     local_decls: &L,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     place: Place<'tcx>,
 ) -> bool
 where
@@ -22,8 +22,8 @@ where
     };
 
     let ty = place.ty(local_decls, tcx).ty;
-    let unsized_tail = || tcx.struct_tail_for_codegen(ty, param_env);
-    match tcx.layout_of(param_env.and(ty)) {
+    let unsized_tail = || tcx.struct_tail_for_codegen(ty, typing_env);
+    match tcx.layout_of(typing_env.as_query_input(ty)) {
         Ok(layout)
             if layout.align.abi <= pack
                 && (layout.is_sized()
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index f743525f359..1afc910ce8f 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -3,7 +3,7 @@ use rustc_middle::bug;
 use rustc_middle::ty::layout::{
     HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement,
 };
-use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
+use rustc_middle::ty::{PseudoCanonicalInput, Ty, TyCtxt};
 
 use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeMachine};
 use crate::interpret::{InterpCx, MemoryKind};
@@ -23,16 +23,16 @@ use crate::interpret::{InterpCx, MemoryKind};
 pub fn check_validity_requirement<'tcx>(
     tcx: TyCtxt<'tcx>,
     kind: ValidityRequirement,
-    param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
+    input: PseudoCanonicalInput<'tcx, Ty<'tcx>>,
 ) -> Result<bool, &'tcx LayoutError<'tcx>> {
-    let layout = tcx.layout_of(param_env_and_ty)?;
+    let layout = tcx.layout_of(input)?;
 
     // There is nothing strict or lax about inhabitedness.
     if kind == ValidityRequirement::Inhabited {
         return Ok(!layout.is_uninhabited());
     }
 
-    let layout_cx = LayoutCx::new(tcx, param_env_and_ty.param_env);
+    let layout_cx = LayoutCx::new(tcx, input.typing_env);
     if kind == ValidityRequirement::Uninit || tcx.sess.opts.unstable_opts.strict_init_checks {
         check_validity_requirement_strict(layout, &layout_cx, kind)
     } else {
@@ -49,7 +49,7 @@ fn check_validity_requirement_strict<'tcx>(
 ) -> Result<bool, &'tcx LayoutError<'tcx>> {
     let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error);
 
-    let mut cx = InterpCx::new(cx.tcx(), rustc_span::DUMMY_SP, cx.param_env, machine);
+    let mut cx = InterpCx::new(cx.tcx(), rustc_span::DUMMY_SP, cx.typing_env.param_env, machine);
 
     let allocated = cx
         .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs
index 0cf27d30c36..9eed1a20f15 100644
--- a/compiler/rustc_const_eval/src/util/compare_types.rs
+++ b/compiler/rustc_const_eval/src/util/compare_types.rs
@@ -5,18 +5,17 @@
 
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, TypingMode, Variance};
+use rustc_middle::ty::{Ty, TyCtxt, TypingEnv, Variance};
 use rustc_trait_selection::traits::ObligationCtxt;
 
 /// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
 pub fn sub_types<'tcx>(
     tcx: TyCtxt<'tcx>,
-    typing_mode: TypingMode<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: TypingEnv<'tcx>,
     src: Ty<'tcx>,
     dest: Ty<'tcx>,
 ) -> bool {
-    relate_types(tcx, typing_mode, param_env, Variance::Covariant, src, dest)
+    relate_types(tcx, typing_env, Variance::Covariant, src, dest)
 }
 
 /// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
@@ -26,8 +25,7 @@ pub fn sub_types<'tcx>(
 /// because we want to check for type equality.
 pub fn relate_types<'tcx>(
     tcx: TyCtxt<'tcx>,
-    typing_mode: TypingMode<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: TypingEnv<'tcx>,
     variance: Variance,
     src: Ty<'tcx>,
     dest: Ty<'tcx>,
@@ -36,8 +34,7 @@ pub fn relate_types<'tcx>(
         return true;
     }
 
-    let mut builder = tcx.infer_ctxt().ignoring_regions();
-    let infcx = builder.build(typing_mode);
+    let (infcx, param_env) = tcx.infer_ctxt().ignoring_regions().build_with_typing_env(typing_env);
     let ocx = ObligationCtxt::new(&infcx);
     let cause = ObligationCause::dummy();
     let src = ocx.normalize(&cause, param_env, src);