about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-05-28 18:21:24 +0000
committerbors <bors@rust-lang.org>2024-05-28 18:21:24 +0000
commit274499dd0ff53b81e93b80520f7afe25adaa2812 (patch)
treed6217d2a53f9ba197558fa54675a461d3f37f91c
parent8c4db851a7bb64173832e6602638204ebbd373a8 (diff)
parentfaabc74625dd42a16a2dbd7685e88c79df5095d4 (diff)
downloadrust-274499dd0ff53b81e93b80520f7afe25adaa2812.tar.gz
rust-274499dd0ff53b81e93b80520f7afe25adaa2812.zip
Auto merge of #125665 - matthiaskrgr:rollup-srkx0v1, r=matthiaskrgr
Rollup of 5 pull requests

Successful merges:

 - #117671 (NVPTX: Avoid PassMode::Direct for args in C abi)
 - #125573 (Migrate `run-make/allow-warnings-cmdline-stability` to `rmake.rs`)
 - #125590 (Add a "Setup Python" action for github-hosted runners and remove unnecessary `CUSTOM_MINGW` environment variable)
 - #125598 (Make `ProofTreeBuilder` actually generic over `Interner`)
 - #125637 (rustfmt fixes)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--.github/workflows/ci.yml9
-rw-r--r--compiler/rustc_middle/src/ty/context.rs7
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs6
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/nvptx64.rs9
-rw-r--r--compiler/rustc_trait_selection/src/solve/alias_relate.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs28
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs22
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs38
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs30
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/build.rs112
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs49
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph.rs11
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs51
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs9
-rw-r--r--compiler/rustc_type_ir/src/interner.rs10
-rw-r--r--library/core/src/ptr/metadata.rs8
-rw-r--r--rustfmt.toml19
-rw-r--r--src/bootstrap/src/core/build_steps/format.rs42
-rw-r--r--src/ci/github-actions/jobs.yml4
-rwxr-xr-xsrc/ci/scripts/install-mingw.sh20
-rwxr-xr-xsrc/ci/scripts/install-msys2.sh27
-rw-r--r--src/tools/run-make-support/src/lib.rs11
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt1
-rw-r--r--tests/assembly/nvptx-c-abi-arg-v7.rs206
-rw-r--r--tests/assembly/nvptx-c-abi-ret-v7.rs230
-rw-r--r--tests/run-make/allow-warnings-cmdline-stability/Makefile16
-rw-r--r--tests/run-make/allow-warnings-cmdline-stability/rmake.rs11
34 files changed, 720 insertions, 286 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0551d44649c..c9d6c56076a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -154,9 +154,12 @@ jobs:
 
       - name: checkout submodules
         run: src/ci/scripts/checkout-submodules.sh
-
-      - name: install MSYS2
-        run: src/ci/scripts/install-msys2.sh
+      
+      - name: Setup Python
+        uses: actions/setup-python@v5
+        with:
+          python-version: '3.x'
+        if: runner.environment == 'github-hosted'
 
       - name: install MinGW
         run: src/ci/scripts/install-mingw.sh
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 51bbe351218..c2219fba023 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -218,6 +218,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.check_and_mk_args(def_id, args)
     }
 
+    fn intern_canonical_goal_evaluation_step(
+        self,
+        step: solve::inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>>,
+    ) -> &'tcx solve::inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>> {
+        self.arena.alloc(step)
+    }
+
     fn parent(self, def_id: Self::DefId) -> Self::DefId {
         self.parent(def_id)
     }
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 5e70b300f33..a54332b6f25 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -219,10 +219,8 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
                     for (i, field) in variant.fields.iter_enumerated() {
                         let field_ty = field.ty(self.tcx, args);
                         if field_ty == *cast_ty {
-                            let place = place.project_deeper(
-                                &[ProjectionElem::Field(i, *cast_ty)],
-                                self.tcx,
-                            );
+                            let place = place
+                                .project_deeper(&[ProjectionElem::Field(i, *cast_ty)], self.tcx);
                             let operand = if operand.is_move() {
                                 Operand::Move(place)
                             } else {
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 6df32169eec..8d7547d03e8 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -691,7 +691,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                                 location,
                                 format!(
                                     "You can't project to field {f:?} of `DynMetadata` because \
-                                         layout is weird and thinks it doesn't have fields."
+                                     layout is weird and thinks it doesn't have fields."
                                 ),
                             );
                         }
diff --git a/compiler/rustc_target/src/abi/call/nvptx64.rs b/compiler/rustc_target/src/abi/call/nvptx64.rs
index f85fa2419f0..c6b6f66e6be 100644
--- a/compiler/rustc_target/src/abi/call/nvptx64.rs
+++ b/compiler/rustc_target/src/abi/call/nvptx64.rs
@@ -11,11 +11,10 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
 }
 
 fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
-    if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 {
-        arg.make_indirect();
-    } else {
-        // FIXME: this is wrong! Need to decide which ABI we really want here.
-        arg.make_direct_deprecated();
+    if arg.layout.is_aggregate() {
+        arg.make_indirect_byval(None);
+    } else if arg.layout.size.bits() < 32 {
+        arg.extend_integer_width_to(32);
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
index 33b30bef683..4d7e2fc2cef 100644
--- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs
+++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
@@ -26,7 +26,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         &mut self,
         goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
     ) -> QueryResult<'tcx> {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
         debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some());
 
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 11524410692..aae6fa9f635 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -83,7 +83,7 @@ pub(super) trait GoalKind<'tcx>:
         assumption: ty::Clause<'tcx>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
-            let tcx = ecx.tcx();
+            let tcx = ecx.interner();
             let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
                 bug!("expected object type in `probe_and_consider_object_bound_candidate`");
             };
@@ -288,8 +288,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect();
         }
 
-        let goal: Goal<'tcx, G> =
-            goal.with(self.tcx(), goal.predicate.with_self_ty(self.tcx(), normalized_self_ty));
+        let goal: Goal<'tcx, G> = goal.with(
+            self.interner(),
+            goal.predicate.with_self_ty(self.interner(), normalized_self_ty),
+        );
         // Vars that show up in the rest of the goal substs may have been constrained by
         // normalizing the self type as well, since type variables are not uniquified.
         let goal = self.resolve_vars_if_possible(goal);
@@ -339,7 +341,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         goal: Goal<'tcx, G>,
         candidates: &mut Vec<Candidate<'tcx>>,
     ) {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let self_ty = goal.predicate.self_ty();
         let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
         let mut consider_impls_for_simplified_type = |simp| {
@@ -455,7 +457,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         goal: Goal<'tcx, G>,
         candidates: &mut Vec<Candidate<'tcx>>,
     ) {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
         for &impl_def_id in trait_impls.blanket_impls() {
             // For every `default impl`, there's always a non-default `impl`
@@ -478,7 +480,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         goal: Goal<'tcx, G>,
         candidates: &mut Vec<Candidate<'tcx>>,
     ) {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let lang_items = tcx.lang_items();
         let trait_def_id = goal.predicate.trait_def_id(tcx);
 
@@ -505,9 +507,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             G::consider_builtin_pointer_like_candidate(self, goal)
         } else if lang_items.fn_ptr_trait() == Some(trait_def_id) {
             G::consider_builtin_fn_ptr_trait_candidate(self, goal)
-        } else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) {
+        } else if let Some(kind) = self.interner().fn_trait_kind_from_def_id(trait_def_id) {
             G::consider_builtin_fn_trait_candidates(self, goal, kind)
-        } else if let Some(kind) = self.tcx().async_fn_trait_kind_from_def_id(trait_def_id) {
+        } else if let Some(kind) = self.interner().async_fn_trait_kind_from_def_id(trait_def_id) {
             G::consider_builtin_async_fn_trait_candidates(self, goal, kind)
         } else if lang_items.async_fn_kind_helper() == Some(trait_def_id) {
             G::consider_builtin_async_fn_kind_helper_candidate(self, goal)
@@ -634,7 +636,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
 
             ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
             ty::Alias(ty::Inherent | ty::Weak, _) => {
-                self.tcx().sess.dcx().span_delayed_bug(
+                self.interner().sess.dcx().span_delayed_bug(
                     DUMMY_SP,
                     format!("could not normalize {self_ty}, it is not WF"),
                 );
@@ -643,7 +645,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         };
 
         for assumption in
-            self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args)
+            self.interner().item_bounds(alias_ty.def_id).instantiate(self.interner(), alias_ty.args)
         {
             candidates.extend(G::probe_and_consider_implied_clause(
                 self,
@@ -673,7 +675,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         goal: Goal<'tcx, G>,
         candidates: &mut Vec<Candidate<'tcx>>,
     ) {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         if !tcx.trait_def(goal.predicate.trait_def_id(tcx)).implement_via_object {
             return;
         }
@@ -764,7 +766,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         goal: Goal<'tcx, G>,
         candidates: &mut Vec<Candidate<'tcx>>,
     ) {
-        let tcx = self.tcx();
+        let tcx = self.interner();
 
         candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(
             |ecx| {
@@ -793,7 +795,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         goal: Goal<'tcx, G>,
         candidates: &mut Vec<Candidate<'tcx>>,
     ) {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> =
             goal.with(tcx, goal.predicate.trait_ref(tcx));
 
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 6f68875e6f6..64d5f725a1f 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -22,7 +22,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
     ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
     ty: Ty<'tcx>,
 ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
-    let tcx = ecx.tcx();
+    let tcx = ecx.interner();
     match *ty.kind() {
         ty::Uint(_)
         | ty::Int(_)
@@ -75,7 +75,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
         }
 
         ty::CoroutineWitness(def_id, args) => Ok(ecx
-            .tcx()
+            .interner()
             .bound_coroutine_hidden_types(def_id)
             .map(|bty| bty.instantiate(tcx, args))
             .collect()),
@@ -151,8 +151,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
         //   "best effort" optimization and `sized_constraint` may return `Some`, even
         //   if the ADT is sized for all possible args.
         ty::Adt(def, args) => {
-            if let Some(sized_crit) = def.sized_constraint(ecx.tcx()) {
-                Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.tcx(), args))])
+            if let Some(sized_crit) = def.sized_constraint(ecx.interner()) {
+                Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), args))])
             } else {
                 Ok(vec![])
             }
@@ -210,10 +210,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
 
         // only when `coroutine_clone` is enabled and the coroutine is movable
         // impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses)
-        ty::Coroutine(def_id, args) => match ecx.tcx().coroutine_movability(def_id) {
+        ty::Coroutine(def_id, args) => match ecx.interner().coroutine_movability(def_id) {
             Movability::Static => Err(NoSolution),
             Movability::Movable => {
-                if ecx.tcx().features().coroutine_clone {
+                if ecx.interner().features().coroutine_clone {
                     let coroutine = args.as_coroutine();
                     Ok(vec![
                         ty::Binder::dummy(coroutine.tupled_upvars_ty()),
@@ -227,9 +227,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
 
         // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
         ty::CoroutineWitness(def_id, args) => Ok(ecx
-            .tcx()
+            .interner()
             .bound_coroutine_hidden_types(def_id)
-            .map(|bty| bty.instantiate(ecx.tcx(), args))
+            .map(|bty| bty.instantiate(ecx.interner(), args))
             .collect()),
     }
 }
@@ -666,7 +666,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
     trait_ref: ty::TraitRef<'tcx>,
     object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
 ) -> Vec<Goal<'tcx, ty::Predicate<'tcx>>> {
-    let tcx = ecx.tcx();
+    let tcx = ecx.interner();
     let mut requirements = vec![];
     requirements.extend(
         tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.args).predicates,
@@ -722,7 +722,7 @@ struct ReplaceProjectionWith<'a, 'tcx> {
 
 impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
     fn interner(&self) -> TyCtxt<'tcx> {
-        self.ecx.tcx()
+        self.ecx.interner()
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
@@ -739,7 +739,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
                     .eq_and_get_goals(
                         self.param_env,
                         alias_ty,
-                        proj.projection_term.expect_ty(self.ecx.tcx()),
+                        proj.projection_term.expect_ty(self.ecx.interner()),
                     )
                     .expect("expected to be able to unify goal projection with dyn's projection"),
             );
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index f6ec6549084..4977807aa6c 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -16,7 +16,6 @@ use crate::solve::{
 use rustc_data_structures::fx::FxHashSet;
 use rustc_index::IndexVec;
 use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
-use rustc_infer::infer::canonical::CanonicalVarValues;
 use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
 use rustc_infer::infer::RegionVariableOrigin;
 use rustc_infer::infer::{InferCtxt, InferOk};
@@ -32,22 +31,24 @@ use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable}
 use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer};
 use rustc_next_trait_solver::resolve::EagerResolver;
 use rustc_span::{Span, DUMMY_SP};
+use rustc_type_ir::CanonicalVarValues;
+use rustc_type_ir::{InferCtxtLike, Interner};
 use std::assert_matches::assert_matches;
 use std::iter;
 use std::ops::Deref;
 
 trait ResponseT<'tcx> {
-    fn var_values(&self) -> CanonicalVarValues<'tcx>;
+    fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>>;
 }
 
 impl<'tcx> ResponseT<'tcx> for Response<TyCtxt<'tcx>> {
-    fn var_values(&self) -> CanonicalVarValues<'tcx> {
+    fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>> {
         self.var_values
     }
 }
 
 impl<'tcx, T> ResponseT<'tcx> for inspect::State<TyCtxt<'tcx>, T> {
-    fn var_values(&self) -> CanonicalVarValues<'tcx> {
+    fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>> {
         self.var_values
     }
 }
@@ -71,7 +72,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             QueryInput {
                 goal,
                 predefined_opaques_in_body: self
-                    .tcx()
+                    .interner()
                     .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }),
             },
         );
@@ -144,7 +145,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             Response {
                 var_values,
                 certainty,
-                external_constraints: self.tcx().mk_external_constraints(external_constraints),
+                external_constraints: self.interner().mk_external_constraints(external_constraints),
             },
         );
 
@@ -160,7 +161,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         maybe_cause: MaybeCause,
     ) -> CanonicalResponse<'tcx> {
         response_no_constraints_raw(
-            self.tcx(),
+            self.interner(),
             self.max_input_universe,
             self.variables,
             Certainty::Maybe(maybe_cause),
@@ -194,7 +195,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned();
             let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| {
                 make_query_region_constraints(
-                    self.tcx(),
+                    self.interner(),
                     region_obligations.iter().map(|r_o| {
                         (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())
                     }),
@@ -239,7 +240,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         );
 
         let Response { var_values, external_constraints, certainty } =
-            response.instantiate(self.tcx(), &instantiation);
+            response.instantiate(self.interner(), &instantiation);
 
         Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values);
 
@@ -260,7 +261,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         infcx: &InferCtxt<'tcx>,
         original_values: &[ty::GenericArg<'tcx>],
         response: &Canonical<'tcx, T>,
-    ) -> CanonicalVarValues<'tcx> {
+    ) -> CanonicalVarValues<TyCtxt<'tcx>> {
         // FIXME: Longterm canonical queries should deal with all placeholders
         // created inside of the query directly instead of returning them to the
         // caller.
@@ -354,7 +355,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         infcx: &InferCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         original_values: &[ty::GenericArg<'tcx>],
-        var_values: CanonicalVarValues<'tcx>,
+        var_values: CanonicalVarValues<TyCtxt<'tcx>>,
     ) {
         assert_eq!(original_values.len(), var_values.len());
 
@@ -393,13 +394,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
 /// evaluating a goal. The `var_values` not only include the bound variables
 /// of the query input, but also contain all unconstrained inference vars
 /// created while evaluating this goal.
-pub(in crate::solve) fn make_canonical_state<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
-    infcx: &InferCtxt<'tcx>,
-    var_values: &[ty::GenericArg<'tcx>],
+pub(in crate::solve) fn make_canonical_state<Infcx, T, I>(
+    infcx: &Infcx,
+    var_values: &[I::GenericArg],
     max_input_universe: ty::UniverseIndex,
     data: T,
-) -> inspect::CanonicalState<TyCtxt<'tcx>, T> {
-    let var_values = CanonicalVarValues { var_values: infcx.tcx.mk_args(var_values) };
+) -> inspect::CanonicalState<I, T>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+    T: TypeFoldable<I>,
+{
+    let var_values = CanonicalVarValues { var_values: infcx.interner().mk_args(var_values) };
     let state = inspect::State { var_values, data };
     let state = state.fold_with(&mut EagerResolver::new(infcx));
     Canonicalizer::canonicalize(
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 4cf0af94811..98ba3feeca1 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -98,7 +98,7 @@ pub struct EvalCtxt<
     // evaluation code.
     tainted: Result<(), NoSolution>,
 
-    pub(super) inspect: ProofTreeBuilder<I>,
+    pub(super) inspect: ProofTreeBuilder<Infcx>,
 }
 
 #[derive(derivative::Derivative)]
@@ -218,7 +218,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
         tcx: TyCtxt<'tcx>,
         search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>,
         canonical_input: CanonicalInput<'tcx>,
-        canonical_goal_evaluation: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+        canonical_goal_evaluation: &mut ProofTreeBuilder<InferCtxt<'tcx>>,
         f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>, Goal<'tcx, ty::Predicate<'tcx>>) -> R,
     ) -> R {
         let intercrate = match search_graph.solver_mode() {
@@ -280,7 +280,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
         tcx: TyCtxt<'tcx>,
         search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>,
         canonical_input: CanonicalInput<'tcx>,
-        goal_evaluation: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+        goal_evaluation: &mut ProofTreeBuilder<InferCtxt<'tcx>>,
     ) -> QueryResult<'tcx> {
         let mut canonical_goal_evaluation =
             goal_evaluation.new_canonical_goal_evaluation(canonical_input);
@@ -347,7 +347,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
         let mut goal_evaluation =
             self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
         let canonical_response = EvalCtxt::evaluate_canonical_goal(
-            self.tcx(),
+            self.interner(),
             self.search_graph,
             canonical_goal,
             &mut goal_evaluation,
@@ -450,7 +450,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
             }
         } else {
             self.infcx.enter_forall(kind, |kind| {
-                let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
+                let goal = goal.with(self.interner(), ty::Binder::dummy(kind));
                 self.add_goal(GoalSource::InstantiateHigherRanked, goal);
                 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             })
@@ -511,7 +511,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
     ///
     /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`.
     fn evaluate_added_goals_step(&mut self) -> Result<Option<Certainty>, NoSolution> {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let mut goals = core::mem::take(&mut self.nested_goals);
 
         // If this loop did not result in any progress, what's our final certainty.
@@ -597,11 +597,13 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
     }
 }
 
-impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
-    pub(super) fn tcx(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
+impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
+    pub(super) fn interner(&self) -> I {
+        self.infcx.interner()
     }
+}
 
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     pub(super) fn next_ty_infer(&mut self) -> Ty<'tcx> {
         let ty = self.infcx.next_ty_var(DUMMY_SP);
         self.inspect.add_var_value(ty);
@@ -759,7 +761,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         // NOTE: this check is purely an optimization, the structural eq would
         // always fail if the term is not an inference variable.
         if term.is_infer() {
-            let tcx = self.tcx();
+            let tcx = self.interner();
             // We need to relate `alias` to `term` treating only the outermost
             // constructor as rigid, relating any contained generic arguments as
             // normal. We do this by first structurally equating the `term`
@@ -1054,10 +1056,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     ) -> Option<ty::Const<'tcx>> {
         use rustc_middle::mir::interpret::ErrorHandled;
         match self.infcx.const_eval_resolve(param_env, unevaluated, DUMMY_SP) {
-            Ok(Some(val)) => Some(ty::Const::new_value(self.tcx(), val, ty)),
+            Ok(Some(val)) => Some(ty::Const::new_value(self.interner(), val, ty)),
             Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None,
             Err(ErrorHandled::Reported(e, _)) => {
-                Some(ty::Const::new_error(self.tcx(), e.into(), ty))
+                Some(ty::Const::new_error(self.interner(), e.into(), ty))
             }
         }
     }
@@ -1070,7 +1072,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         principal: ty::PolyTraitRef<'tcx>,
         mut supertrait_visitor: impl FnMut(&mut Self, ty::PolyTraitRef<'tcx>, usize, Option<usize>),
     ) {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let mut offset = 0;
         prepare_vtable_segments::<()>(tcx, principal, |segment| {
             match segment {
@@ -1112,7 +1114,7 @@ struct ReplaceAliasWithInfer<'me, 'a, 'tcx> {
 
 impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'_, '_, 'tcx> {
     fn interner(&self) -> TyCtxt<'tcx> {
-        self.ecx.tcx()
+        self.ecx.interner()
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
index 3c633362648..84c04900ae4 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
@@ -3,18 +3,16 @@
 //! This code is *a bit* of a mess and can hopefully be
 //! mostly ignored. For a general overview of how it works,
 //! see the comment on [ProofTreeBuilder].
+use std::marker::PhantomData;
 use std::mem;
 
 use crate::solve::eval_ctxt::canonical;
 use crate::solve::{self, inspect, GenerateProofTree};
-use rustc_infer::infer::InferCtxt;
 use rustc_middle::bug;
-use rustc_middle::infer::canonical::CanonicalVarValues;
-use rustc_middle::ty::{self, TyCtxt};
 use rustc_next_trait_solver::solve::{
     CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult,
 };
-use rustc_type_ir::Interner;
+use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
 
 /// The core data structure when building proof trees.
 ///
@@ -36,7 +34,11 @@ use rustc_type_ir::Interner;
 /// trees. At the end of trait solving `ProofTreeBuilder::finalize`
 /// is called to recursively convert the whole structure to a
 /// finished proof tree.
-pub(in crate::solve) struct ProofTreeBuilder<I: Interner> {
+pub(in crate::solve) struct ProofTreeBuilder<
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner = <Infcx as InferCtxtLike>::Interner,
+> {
+    _infcx: PhantomData<Infcx>,
     state: Option<Box<DebugSolver<I>>>,
 }
 
@@ -229,36 +231,36 @@ impl<I: Interner> WipProbeStep<I> {
     }
 }
 
-// FIXME: Genericize this impl.
-impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
-    fn new(state: impl Into<DebugSolver<TyCtxt<'tcx>>>) -> ProofTreeBuilder<TyCtxt<'tcx>> {
-        ProofTreeBuilder { state: Some(Box::new(state.into())) }
+impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
+    fn new(state: impl Into<DebugSolver<I>>) -> ProofTreeBuilder<Infcx> {
+        ProofTreeBuilder { state: Some(Box::new(state.into())), _infcx: PhantomData }
     }
 
-    fn opt_nested<T: Into<DebugSolver<TyCtxt<'tcx>>>>(
-        &self,
-        state: impl FnOnce() -> Option<T>,
-    ) -> Self {
+    fn opt_nested<T: Into<DebugSolver<I>>>(&self, state: impl FnOnce() -> Option<T>) -> Self {
         ProofTreeBuilder {
             state: self.state.as_ref().and_then(|_| Some(state()?.into())).map(Box::new),
+            _infcx: PhantomData,
         }
     }
 
-    fn nested<T: Into<DebugSolver<TyCtxt<'tcx>>>>(&self, state: impl FnOnce() -> T) -> Self {
-        ProofTreeBuilder { state: self.state.as_ref().map(|_| Box::new(state().into())) }
+    fn nested<T: Into<DebugSolver<I>>>(&self, state: impl FnOnce() -> T) -> Self {
+        ProofTreeBuilder {
+            state: self.state.as_ref().map(|_| Box::new(state().into())),
+            _infcx: PhantomData,
+        }
     }
 
-    fn as_mut(&mut self) -> Option<&mut DebugSolver<TyCtxt<'tcx>>> {
+    fn as_mut(&mut self) -> Option<&mut DebugSolver<I>> {
         self.state.as_deref_mut()
     }
 
-    pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<TyCtxt<'tcx>> {
-        let mut nested = ProofTreeBuilder { state: self.state.take() };
+    pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<Infcx> {
+        let mut nested = ProofTreeBuilder { state: self.state.take(), _infcx: PhantomData };
         nested.enter_probe();
         nested
     }
 
-    pub fn finalize(self) -> Option<inspect::GoalEvaluation<TyCtxt<'tcx>>> {
+    pub fn finalize(self) -> Option<inspect::GoalEvaluation<I>> {
         match *self.state? {
             DebugSolver::GoalEvaluation(wip_goal_evaluation) => {
                 Some(wip_goal_evaluation.finalize())
@@ -267,21 +269,19 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
         }
     }
 
-    pub fn new_maybe_root(
-        generate_proof_tree: GenerateProofTree,
-    ) -> ProofTreeBuilder<TyCtxt<'tcx>> {
+    pub fn new_maybe_root(generate_proof_tree: GenerateProofTree) -> ProofTreeBuilder<Infcx> {
         match generate_proof_tree {
             GenerateProofTree::No => ProofTreeBuilder::new_noop(),
             GenerateProofTree::Yes => ProofTreeBuilder::new_root(),
         }
     }
 
-    pub fn new_root() -> ProofTreeBuilder<TyCtxt<'tcx>> {
+    pub fn new_root() -> ProofTreeBuilder<Infcx> {
         ProofTreeBuilder::new(DebugSolver::Root)
     }
 
-    pub fn new_noop() -> ProofTreeBuilder<TyCtxt<'tcx>> {
-        ProofTreeBuilder { state: None }
+    pub fn new_noop() -> ProofTreeBuilder<Infcx> {
+        ProofTreeBuilder { state: None, _infcx: PhantomData }
     }
 
     pub fn is_noop(&self) -> bool {
@@ -290,10 +290,10 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
 
     pub(in crate::solve) fn new_goal_evaluation(
         &mut self,
-        goal: Goal<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
-        orig_values: &[ty::GenericArg<'tcx>],
+        goal: Goal<I, I::Predicate>,
+        orig_values: &[I::GenericArg],
         kind: solve::GoalEvaluationKind,
-    ) -> ProofTreeBuilder<TyCtxt<'tcx>> {
+    ) -> ProofTreeBuilder<Infcx> {
         self.opt_nested(|| match kind {
             solve::GoalEvaluationKind::Root => Some(WipGoalEvaluation {
                 uncanonicalized_goal: goal,
@@ -306,8 +306,8 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
 
     pub fn new_canonical_goal_evaluation(
         &mut self,
-        goal: CanonicalInput<TyCtxt<'tcx>>,
-    ) -> ProofTreeBuilder<TyCtxt<'tcx>> {
+        goal: CanonicalInput<I>,
+    ) -> ProofTreeBuilder<Infcx> {
         self.nested(|| WipCanonicalGoalEvaluation {
             goal,
             kind: None,
@@ -318,12 +318,13 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
 
     pub fn finalize_canonical_goal_evaluation(
         &mut self,
-        tcx: TyCtxt<'tcx>,
-    ) -> Option<&'tcx inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>>> {
+        tcx: I,
+    ) -> Option<I::CanonicalGoalEvaluationStepRef> {
         self.as_mut().map(|this| match this {
             DebugSolver::CanonicalGoalEvaluation(evaluation) => {
                 let final_revision = mem::take(&mut evaluation.final_revision).unwrap();
-                let final_revision = &*tcx.arena.alloc(final_revision.finalize());
+                let final_revision =
+                    tcx.intern_canonical_goal_evaluation_step(final_revision.finalize());
                 let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision };
                 assert_eq!(evaluation.kind.replace(kind), None);
                 final_revision
@@ -334,7 +335,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
 
     pub fn canonical_goal_evaluation(
         &mut self,
-        canonical_goal_evaluation: ProofTreeBuilder<TyCtxt<'tcx>>,
+        canonical_goal_evaluation: ProofTreeBuilder<Infcx>,
     ) {
         if let Some(this) = self.as_mut() {
             match (this, *canonical_goal_evaluation.state.unwrap()) {
@@ -350,10 +351,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
         }
     }
 
-    pub fn canonical_goal_evaluation_kind(
-        &mut self,
-        kind: WipCanonicalGoalEvaluationKind<TyCtxt<'tcx>>,
-    ) {
+    pub fn canonical_goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind<I>) {
         if let Some(this) = self.as_mut() {
             match this {
                 DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => {
@@ -364,7 +362,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
         }
     }
 
-    pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<TyCtxt<'tcx>>) {
+    pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<Infcx>) {
         if let Some(this) = self.as_mut() {
             match this {
                 DebugSolver::Root => *this = *goal_evaluation.state.unwrap(),
@@ -378,9 +376,9 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
 
     pub fn new_goal_evaluation_step(
         &mut self,
-        var_values: CanonicalVarValues<'tcx>,
-        instantiated_goal: QueryInput<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
-    ) -> ProofTreeBuilder<TyCtxt<'tcx>> {
+        var_values: ty::CanonicalVarValues<I>,
+        instantiated_goal: QueryInput<I, I::Predicate>,
+    ) -> ProofTreeBuilder<Infcx> {
         self.nested(|| WipCanonicalGoalEvaluationStep {
             var_values: var_values.var_values.to_vec(),
             instantiated_goal,
@@ -394,7 +392,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
         })
     }
 
-    pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<TyCtxt<'tcx>>) {
+    pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<Infcx>) {
         if let Some(this) = self.as_mut() {
             match (this, *goal_evaluation_step.state.unwrap()) {
                 (
@@ -408,7 +406,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
         }
     }
 
-    pub fn add_var_value<T: Into<ty::GenericArg<'tcx>>>(&mut self, arg: T) {
+    pub fn add_var_value<T: Into<I::GenericArg>>(&mut self, arg: T) {
         match self.as_mut() {
             None => {}
             Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
@@ -435,7 +433,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
         }
     }
 
-    pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind<TyCtxt<'tcx>>) {
+    pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind<I>) {
         match self.as_mut() {
             None => {}
             Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
@@ -446,11 +444,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
         }
     }
 
-    pub fn probe_final_state(
-        &mut self,
-        infcx: &InferCtxt<'tcx>,
-        max_input_universe: ty::UniverseIndex,
-    ) {
+    pub fn probe_final_state(&mut self, infcx: &Infcx, max_input_universe: ty::UniverseIndex) {
         match self.as_mut() {
             None => {}
             Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
@@ -469,24 +463,24 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
 
     pub fn add_normalizes_to_goal(
         &mut self,
-        infcx: &InferCtxt<'tcx>,
+        infcx: &Infcx,
         max_input_universe: ty::UniverseIndex,
-        goal: Goal<TyCtxt<'tcx>, ty::NormalizesTo<'tcx>>,
+        goal: Goal<I, ty::NormalizesTo<I>>,
     ) {
         self.add_goal(
             infcx,
             max_input_universe,
             GoalSource::Misc,
-            goal.with(infcx.tcx, goal.predicate),
+            goal.with(infcx.interner(), goal.predicate),
         );
     }
 
     pub fn add_goal(
         &mut self,
-        infcx: &InferCtxt<'tcx>,
+        infcx: &Infcx,
         max_input_universe: ty::UniverseIndex,
         source: GoalSource,
-        goal: Goal<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
+        goal: Goal<I, I::Predicate>,
     ) {
         match self.as_mut() {
             None => {}
@@ -505,9 +499,9 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
 
     pub(crate) fn record_impl_args(
         &mut self,
-        infcx: &InferCtxt<'tcx>,
+        infcx: &Infcx,
         max_input_universe: ty::UniverseIndex,
-        impl_args: ty::GenericArgsRef<'tcx>,
+        impl_args: I::GenericArgs,
     ) {
         match self.as_mut() {
             Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
@@ -540,7 +534,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
         }
     }
 
-    pub fn finish_probe(mut self) -> ProofTreeBuilder<TyCtxt<'tcx>> {
+    pub fn finish_probe(mut self) -> ProofTreeBuilder<Infcx> {
         match self.as_mut() {
             None => {}
             Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
@@ -555,7 +549,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
         self
     }
 
-    pub fn query_result(&mut self, result: QueryResult<TyCtxt<'tcx>>) {
+    pub fn query_result(&mut self, result: QueryResult<I>) {
         if let Some(this) = self.as_mut() {
             match this {
                 DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => {
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 60722d3618f..a432090f78c 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -133,7 +133,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
     }
 
     fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> {
-        if self.tcx().check_is_object_safe(trait_def_id) {
+        if self.interner().check_is_object_safe(trait_def_id) {
             self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         } else {
             Err(NoSolution)
@@ -274,7 +274,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         if let ty::Alias(..) = ty.kind() {
             let normalized_ty = self.next_ty_infer();
             let alias_relate_goal = Goal::new(
-                self.tcx(),
+                self.interner(),
                 param_env,
                 ty::PredicateKind::AliasRelate(
                     ty.into(),
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs
index c9621e705e5..362c4072278 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs
@@ -12,7 +12,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         if let Some(normalized_const) = self.try_const_eval_resolve(
             goal.param_env,
             ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args),
-            self.tcx()
+            self.interner()
                 .type_of(goal.predicate.alias.def_id)
                 .no_bound_vars()
                 .expect("const ty should not rely on other generics"),
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
index 2146a2c2f08..41b2b9cd4d2 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
@@ -15,7 +15,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         &mut self,
         goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
     ) -> QueryResult<'tcx> {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let inherent = goal.predicate.alias.expect_ty(tcx);
 
         let impl_def_id = tcx.parent(inherent.def_id);
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 7ef8373663b..7fd2a3801cc 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -54,7 +54,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         &mut self,
         goal: Goal<'tcx, NormalizesTo<'tcx>>,
     ) -> QueryResult<'tcx> {
-        match goal.predicate.alias.kind(self.tcx()) {
+        match goal.predicate.alias.kind(self.interner()) {
             ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
                 let candidates = self.assemble_and_evaluate_candidates(goal);
                 self.merge_candidates(candidates)
@@ -107,7 +107,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if let Some(projection_pred) = assumption.as_projection_clause() {
             if projection_pred.projection_def_id() == goal.predicate.def_id() {
-                let tcx = ecx.tcx();
+                let tcx = ecx.interner();
                 ecx.probe_trait_candidate(source).enter(|ecx| {
                     let assumption_projection_pred =
                         ecx.instantiate_binder_with_infer(projection_pred);
@@ -142,7 +142,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         goal: Goal<'tcx, NormalizesTo<'tcx>>,
         impl_def_id: DefId,
     ) -> Result<Candidate<'tcx>, NoSolution> {
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
 
         let goal_trait_ref = goal.predicate.alias.trait_ref(tcx);
         let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
@@ -290,8 +290,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
-        ecx.tcx().dcx().span_delayed_bug(
-            ecx.tcx().def_span(goal.predicate.def_id()),
+        ecx.interner().dcx().span_delayed_bug(
+            ecx.interner().def_span(goal.predicate.def_id()),
             "associated types not allowed on auto traits",
         );
         Err(NoSolution)
@@ -337,7 +337,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         goal: Goal<'tcx, Self>,
         goal_kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution> {
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         let tupled_inputs_and_output =
             match structural_traits::extract_tupled_inputs_and_output_from_callable(
                 tcx,
@@ -380,7 +380,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         goal: Goal<'tcx, Self>,
         goal_kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution> {
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
 
         let env_region = match goal_kind {
             ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2),
@@ -493,7 +493,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         }
 
         let upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind(
-            ecx.tcx(),
+            ecx.interner(),
             goal_kind,
             tupled_inputs_ty.expect_ty(),
             tupled_upvars_ty.expect_ty(),
@@ -518,7 +518,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
         assert_eq!(metadata_def_id, goal.predicate.def_id());
         ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
@@ -606,7 +606,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         };
 
         // Coroutines are not futures unless they come from `async` desugaring
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         if !tcx.coroutine_is_async(def_id) {
             return Err(NoSolution);
         }
@@ -618,7 +618,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
             goal,
             ty::ProjectionPredicate {
-                projection_term: ty::AliasTerm::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
+                projection_term: ty::AliasTerm::new(
+                    ecx.interner(),
+                    goal.predicate.def_id(),
+                    [self_ty],
+                ),
                 term,
             }
             .upcast(tcx),
@@ -638,7 +642,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         };
 
         // Coroutines are not Iterators unless they come from `gen` desugaring
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         if !tcx.coroutine_is_gen(def_id) {
             return Err(NoSolution);
         }
@@ -650,7 +654,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
             goal,
             ty::ProjectionPredicate {
-                projection_term: ty::AliasTerm::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
+                projection_term: ty::AliasTerm::new(
+                    ecx.interner(),
+                    goal.predicate.def_id(),
+                    [self_ty],
+                ),
                 term,
             }
             .upcast(tcx),
@@ -677,7 +685,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         };
 
         // Coroutines are not AsyncIterators unless they come from `gen` desugaring
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         if !tcx.coroutine_is_async_gen(def_id) {
             return Err(NoSolution);
         }
@@ -713,7 +721,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         };
 
         // `async`-desugared coroutines do not implement the coroutine trait
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         if !tcx.is_general_coroutine(def_id) {
             return Err(NoSolution);
         }
@@ -735,7 +743,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
             goal,
             ty::ProjectionPredicate {
                 projection_term: ty::AliasTerm::new(
-                    ecx.tcx(),
+                    ecx.interner(),
                     goal.predicate.def_id(),
                     [self_ty, coroutine.resume_ty()],
                 ),
@@ -784,7 +792,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
             | ty::Slice(_)
             | ty::Dynamic(_, _, _)
             | ty::Tuple(_)
-            | ty::Error(_) => self_ty.discriminant_ty(ecx.tcx()),
+            | ty::Error(_) => self_ty.discriminant_ty(ecx.interner()),
 
             // We do not call `Ty::discriminant_ty` on alias, param, or placeholder
             // types, which return `<self_ty as DiscriminantKind>::Discriminant`
@@ -831,7 +839,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
             | ty::Str
             | ty::Slice(_)
             | ty::Tuple(_)
-            | ty::Error(_) => self_ty.async_destructor_ty(ecx.tcx(), goal.param_env),
+            | ty::Error(_) => self_ty.async_destructor_ty(ecx.interner(), goal.param_env),
 
             // We do not call `Ty::async_destructor_ty` on alias, param, or placeholder
             // types, which return `<self_ty as AsyncDestruct>::AsyncDestructor`
@@ -887,8 +895,9 @@ fn fetch_eligible_assoc_item_def<'tcx>(
     trait_assoc_def_id: DefId,
     impl_def_id: DefId,
 ) -> Result<Option<LeafDef>, NoSolution> {
-    let node_item = specialization_graph::assoc_def(ecx.tcx(), impl_def_id, trait_assoc_def_id)
-        .map_err(|ErrorGuaranteed { .. }| NoSolution)?;
+    let node_item =
+        specialization_graph::assoc_def(ecx.interner(), impl_def_id, trait_assoc_def_id)
+            .map_err(|ErrorGuaranteed { .. }| NoSolution)?;
 
     let eligible = if node_item.is_final() {
         // Non-specializable items are always projectable.
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs
index 3b83d347276..67ec2f3be48 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs
@@ -15,7 +15,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         &mut self,
         goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
     ) -> QueryResult<'tcx> {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let opaque_ty = goal.predicate.alias;
         let expected = goal.predicate.term.ty().expect("no such thing as an opaque const");
 
@@ -31,7 +31,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
                     return Err(NoSolution);
                 }
                 // FIXME: This may have issues when the args contain aliases...
-                match self.tcx().uses_unique_placeholders_ignoring_regions(opaque_ty.args) {
+                match self.interner().uses_unique_placeholders_ignoring_regions(opaque_ty.args) {
                     Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => {
                         return self.evaluate_added_goals_and_make_canonical_response(
                             Certainty::AMBIGUOUS,
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
index 109a9e9671f..5442b9ccffc 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
@@ -14,7 +14,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         &mut self,
         goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
     ) -> QueryResult<'tcx> {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let weak_ty = goal.predicate.alias;
 
         // Check where clauses
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 8fa78e49dc6..cae73cc2d07 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -11,7 +11,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         &mut self,
         goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
     ) -> QueryResult<'tcx> {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let projection_term = goal.predicate.projection_term.to_term(tcx);
         let goal = goal.with(
             tcx,
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs
index 6be623b6044..f1b8bf4676e 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs
@@ -3,6 +3,7 @@ use std::mem;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::Idx;
 use rustc_index::IndexVec;
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::dep_graph::dep_kinds;
 use rustc_middle::traits::solve::CacheData;
 use rustc_middle::traits::solve::EvaluationCache;
@@ -261,10 +262,10 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
         &mut self,
         tcx: TyCtxt<'tcx>,
         input: CanonicalInput<TyCtxt<'tcx>>,
-        inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+        inspect: &mut ProofTreeBuilder<InferCtxt<'tcx>>,
         mut prove_goal: impl FnMut(
             &mut Self,
-            &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+            &mut ProofTreeBuilder<InferCtxt<'tcx>>,
         ) -> QueryResult<TyCtxt<'tcx>>,
     ) -> QueryResult<TyCtxt<'tcx>> {
         self.check_invariants();
@@ -426,7 +427,7 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
         tcx: TyCtxt<'tcx>,
         input: CanonicalInput<TyCtxt<'tcx>>,
         available_depth: Limit,
-        inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+        inspect: &mut ProofTreeBuilder<InferCtxt<'tcx>>,
     ) -> Option<QueryResult<TyCtxt<'tcx>>> {
         let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self
             .global_cache(tcx)
@@ -473,11 +474,11 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
         &mut self,
         tcx: TyCtxt<'tcx>,
         input: CanonicalInput<TyCtxt<'tcx>>,
-        inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+        inspect: &mut ProofTreeBuilder<InferCtxt<'tcx>>,
         prove_goal: &mut F,
     ) -> StepResult<TyCtxt<'tcx>>
     where
-        F: FnMut(&mut Self, &mut ProofTreeBuilder<TyCtxt<'tcx>>) -> QueryResult<TyCtxt<'tcx>>,
+        F: FnMut(&mut Self, &mut ProofTreeBuilder<InferCtxt<'tcx>>) -> QueryResult<TyCtxt<'tcx>>,
     {
         let result = prove_goal(self, inspect);
         let stack_entry = self.pop_stack();
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index e59eef22f41..67dd3fa85fa 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -42,7 +42,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
         impl_def_id: DefId,
     ) -> Result<Candidate<'tcx>, NoSolution> {
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
 
         let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
         let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
@@ -181,7 +181,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             return Err(NoSolution);
         }
 
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
 
         ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
             let nested_obligations = tcx
@@ -235,7 +235,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         }
 
         // The regions of a type don't affect the size of the type
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         // We should erase regions from both the param-env and type, since both
         // may have infer regions. Specifically, after canonicalizing and instantiating,
         // early bound regions turn into region vars in both the new and old solver.
@@ -296,7 +296,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             return Err(NoSolution);
         }
 
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         let tupled_inputs_and_output =
             match structural_traits::extract_tupled_inputs_and_output_from_callable(
                 tcx,
@@ -337,7 +337,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             return Err(NoSolution);
         }
 
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         let (tupled_inputs_and_output_and_coroutine, nested_preds) =
             structural_traits::extract_tupled_inputs_and_output_from_async_callable(
                 tcx,
@@ -447,7 +447,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         };
 
         // Coroutines are not futures unless they come from `async` desugaring
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         if !tcx.coroutine_is_async(def_id) {
             return Err(NoSolution);
         }
@@ -473,7 +473,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         };
 
         // Coroutines are not iterators unless they come from `gen` desugaring
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         if !tcx.coroutine_is_gen(def_id) {
             return Err(NoSolution);
         }
@@ -499,7 +499,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         };
 
         // Coroutines are not iterators unless they come from `gen` desugaring
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         if !tcx.coroutine_is_gen(def_id) {
             return Err(NoSolution);
         }
@@ -523,7 +523,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         };
 
         // Coroutines are not iterators unless they come from `gen` desugaring
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         if !tcx.coroutine_is_async_gen(def_id) {
             return Err(NoSolution);
         }
@@ -550,7 +550,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         };
 
         // `async`-desugared coroutines do not implement the coroutine trait
-        let tcx = ecx.tcx();
+        let tcx = ecx.interner();
         if !tcx.is_general_coroutine(def_id) {
             return Err(NoSolution);
         }
@@ -625,10 +625,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
 
         // Erase regions because we compute layouts in `rustc_transmute`,
         // which will ICE for region vars.
-        let args = ecx.tcx().erase_regions(goal.predicate.trait_ref.args);
+        let args = ecx.interner().erase_regions(goal.predicate.trait_ref.args);
 
         let Some(assume) =
-            rustc_transmute::Assume::from_const(ecx.tcx(), goal.param_env, args.const_at(2))
+            rustc_transmute::Assume::from_const(ecx.interner(), goal.param_env, args.const_at(2))
         else {
             return Err(NoSolution);
         };
@@ -675,7 +675,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                 return vec![];
             };
 
-            let goal = goal.with(ecx.tcx(), (a_ty, b_ty));
+            let goal = goal.with(ecx.interner(), (a_ty, b_ty));
             match (a_ty.kind(), b_ty.kind()) {
                 (ty::Infer(ty::TyVar(..)), ..) => bug!("unexpected infer {a_ty:?} {b_ty:?}"),
 
@@ -741,7 +741,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
         b_region: ty::Region<'tcx>,
     ) -> Vec<Candidate<'tcx>> {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let Goal { predicate: (a_ty, _b_ty), .. } = goal;
 
         let mut responses = vec![];
@@ -787,7 +787,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
         b_region: ty::Region<'tcx>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let Goal { predicate: (a_ty, _), .. } = goal;
 
         // Can only unsize to an object-safe trait.
@@ -837,8 +837,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         let a_auto_traits: FxIndexSet<DefId> = a_data
             .auto_traits()
             .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
-                supertrait_def_ids(self.tcx(), principal_def_id)
-                    .filter(|def_id| self.tcx().trait_is_auto(*def_id))
+                supertrait_def_ids(self.interner(), principal_def_id)
+                    .filter(|def_id| self.interner().trait_is_auto(*def_id))
             }))
             .collect();
 
@@ -907,7 +907,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             ecx.add_goal(
                 GoalSource::ImplWhereBound,
                 Goal::new(
-                    ecx.tcx(),
+                    ecx.interner(),
                     param_env,
                     ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
                 ),
@@ -956,7 +956,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         a_args: ty::GenericArgsRef<'tcx>,
         b_args: ty::GenericArgsRef<'tcx>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let Goal { predicate: (_a_ty, b_ty), .. } = goal;
 
         let unsizing_params = tcx.unsizing_params_for_adt(def.did());
@@ -1017,7 +1017,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         a_tys: &'tcx ty::List<Ty<'tcx>>,
         b_tys: &'tcx ty::List<Ty<'tcx>>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
-        let tcx = self.tcx();
+        let tcx = self.interner();
         let Goal { predicate: (_a_ty, b_ty), .. } = goal;
 
         let (&a_last_ty, a_rest_tys) = a_tys.split_last().unwrap();
@@ -1077,9 +1077,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             // takes precedence over the structural auto trait candidate being
             // assembled.
             ty::Coroutine(def_id, _)
-                if Some(goal.predicate.def_id()) == self.tcx().lang_items().unpin_trait() =>
+                if Some(goal.predicate.def_id()) == self.interner().lang_items().unpin_trait() =>
             {
-                match self.tcx().coroutine_movability(def_id) {
+                match self.interner().coroutine_movability(def_id) {
                     Movability::Static => Some(Err(NoSolution)),
                     Movability::Movable => Some(
                         self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
@@ -1124,7 +1124,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             | ty::Tuple(_)
             | ty::Adt(_, _) => {
                 let mut disqualifying_impl = None;
-                self.tcx().for_each_relevant_impl(
+                self.interner().for_each_relevant_impl(
                     goal.predicate.def_id(),
                     goal.predicate.self_ty(),
                     |impl_def_id| {
@@ -1164,7 +1164,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
                     .into_iter()
                     .map(|ty| {
                         ecx.enter_forall(ty, |ty| {
-                            goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty))
+                            goal.with(
+                                ecx.interner(),
+                                goal.predicate.with_self_ty(ecx.interner(), ty),
+                            )
                         })
                     })
                     .collect::<Vec<_>>(),
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index e7e893f27da..7b1dfecfee2 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -132,7 +132,14 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
 }
 
 pub trait Predicate<I: Interner<Predicate = Self>>:
-    Copy + Debug + Hash + Eq + TypeSuperVisitable<I> + TypeSuperFoldable<I> + Flags
+    Copy
+    + Debug
+    + Hash
+    + Eq
+    + TypeSuperVisitable<I>
+    + TypeSuperFoldable<I>
+    + Flags
+    + UpcastFrom<I, ty::NormalizesTo<I>>
 {
     fn is_coinductive(self, interner: I) -> bool;
 }
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index e49db171a53..2a228c973d3 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -3,6 +3,7 @@ use std::fmt::Debug;
 use std::hash::Hash;
 use std::ops::Deref;
 
+use crate::fold::TypeFoldable;
 use crate::inherent::*;
 use crate::ir_print::IrPrint;
 use crate::solve::inspect::CanonicalGoalEvaluationStep;
@@ -90,7 +91,7 @@ pub trait Interner:
     type PlaceholderRegion: PlaceholderLike;
 
     // Predicates
-    type ParamEnv: Copy + Debug + Hash + Eq;
+    type ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable<Self>;
     type Predicate: Predicate<Self>;
     type Clause: Clause<Self>;
     type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
@@ -114,15 +115,18 @@ pub trait Interner:
     ) -> (ty::TraitRef<Self>, Self::OwnItemArgs);
 
     fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs;
-
     fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs;
-
     fn check_and_mk_args(
         self,
         def_id: Self::DefId,
         args: impl IntoIterator<Item: Into<Self::GenericArg>>,
     ) -> Self::GenericArgs;
 
+    fn intern_canonical_goal_evaluation_step(
+        self,
+        step: CanonicalGoalEvaluationStep<Self>,
+    ) -> Self::CanonicalGoalEvaluationStepRef;
+
     fn parent(self, def_id: Self::DefId) -> Self::DefId;
 
     fn recursion_limit(self) -> usize;
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index e501970b580..6dfeb66694d 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -209,18 +209,14 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
         // Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the
         // `Send` part!
         // SAFETY: DynMetadata always contains a valid vtable pointer
-        return unsafe {
-            crate::intrinsics::vtable_size(self.vtable_ptr() as *const ())
-        };
+        return unsafe { crate::intrinsics::vtable_size(self.vtable_ptr() as *const ()) };
     }
 
     /// Returns the alignment of the type associated with this vtable.
     #[inline]
     pub fn align_of(self) -> usize {
         // SAFETY: DynMetadata always contains a valid vtable pointer
-        return unsafe {
-            crate::intrinsics::vtable_align(self.vtable_ptr() as *const ())
-        };
+        return unsafe { crate::intrinsics::vtable_align(self.vtable_ptr() as *const ()) };
     }
 
     /// Returns the size and alignment together as a `Layout`
diff --git a/rustfmt.toml b/rustfmt.toml
index ef56059feb1..b78e96d5872 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -3,25 +3,18 @@ version = "Two"
 use_small_heuristics = "Max"
 merge_derives = false
 
-# by default we ignore everything in the repository
-# tidy only checks files which are not ignored, each entry follows gitignore style
+# Files to ignore. Each entry uses gitignore syntax, but `!` prefixes aren't allowed.
 ignore = [
     "/build/",
     "/*-build/",
     "/build-*/",
     "/vendor/",
 
-    # tests for now are not formatted, as they are sometimes pretty-printing constrained
-    # (and generally rustfmt can move around comments in UI-testing incompatible ways)
-    "/tests/*",
+    # Tests for now are not formatted, as they are sometimes pretty-printing constrained
+    # (and generally rustfmt can move around comments in UI-testing incompatible ways).
+    "/tests/",
 
-    # but we still want to format rmake.rs files in tests/run-make/ so we need to do this
-    # dance to avoid the parent directory from being excluded
-    "!/tests/run-make/",
-    "/tests/run-make/*/*.rs",
-    "!/tests/run-make/*/rmake.rs",
-
-    # do not format submodules
+    # Do not format submodules.
     # FIXME: sync submodule list with tidy/bootstrap/etc
     # tidy/src/walk.rs:filter_dirs
     "library/backtrace",
@@ -43,7 +36,7 @@ ignore = [
     "src/tools/rustc-perf",
     "src/tools/rustfmt",
 
-    # these are ignored by a standard cargo fmt run
+    # These are ignored by a standard cargo fmt run.
     "compiler/rustc_codegen_cranelift/scripts",
     "compiler/rustc_codegen_cranelift/example/gen_block_iterate.rs", # uses edition 2024
 ]
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index d9dc34c0137..44f575b51da 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -12,8 +12,8 @@ use std::sync::mpsc::SyncSender;
 
 fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl FnMut(bool) -> bool {
     let mut cmd = Command::new(rustfmt);
-    // avoid the submodule config paths from coming into play,
-    // we only allow a single global config for the workspace for now
+    // Avoid the submodule config paths from coming into play. We only allow a single global config
+    // for the workspace for now.
     cmd.arg("--config-path").arg(&src.canonicalize().unwrap());
     cmd.arg("--edition").arg("2021");
     cmd.arg("--unstable-features");
@@ -24,7 +24,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
     cmd.args(paths);
     let cmd_debug = format!("{cmd:?}");
     let mut cmd = cmd.spawn().expect("running rustfmt");
-    // poor man's async: return a closure that'll wait for rustfmt's completion
+    // Poor man's async: return a closure that'll wait for rustfmt's completion.
     move |block: bool| -> bool {
         if !block {
             match cmd.try_wait() {
@@ -72,7 +72,7 @@ fn verify_rustfmt_version(build: &Builder<'_>) -> bool {
     !program_out_of_date(&stamp_file, &version)
 }
 
-/// Updates the last rustfmt version used
+/// Updates the last rustfmt version used.
 fn update_rustfmt_version(build: &Builder<'_>) {
     let Some((version, stamp_file)) = get_rustfmt_version(build) else {
         return;
@@ -115,8 +115,15 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
     let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config));
     let mut fmt_override = ignore::overrides::OverrideBuilder::new(&build.src);
     for ignore in rustfmt_config.ignore {
-        if let Some(ignore) = ignore.strip_prefix('!') {
-            fmt_override.add(ignore).expect(ignore);
+        if ignore.starts_with('!') {
+            // A `!`-prefixed entry could be added as a whitelisted entry in `fmt_override`, i.e.
+            // strip the `!` prefix. But as soon as whitelisted entries are added, an
+            // `OverrideBuilder` will only traverse those whitelisted entries, and won't traverse
+            // any files that aren't explicitly mentioned. No bueno! Maybe there's a way to combine
+            // explicit whitelisted entries and traversal of unmentioned files, but for now just
+            // forbid such entries.
+            eprintln!("`!`-prefixed entries are not supported in rustfmt.toml, sorry");
+            crate::exit!(1);
         } else {
             fmt_override.add(&format!("!{ignore}")).expect(&ignore);
         }
@@ -168,9 +175,10 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
                 untracked_count += 1;
                 fmt_override.add(&format!("!/{untracked_path}")).expect(untracked_path);
             }
-            // Only check modified files locally to speed up runtime.
-            // We still check all files in CI to avoid bugs in `get_modified_rs_files` letting regressions slip through;
-            // we also care about CI time less since this is still very fast compared to building the compiler.
+            // Only check modified files locally to speed up runtime. We still check all files in
+            // CI to avoid bugs in `get_modified_rs_files` letting regressions slip through; we
+            // also care about CI time less since this is still very fast compared to building the
+            // compiler.
             if !CiEnv::is_ci() && paths.is_empty() {
                 match get_modified_rs_files(build) {
                     Ok(Some(files)) => {
@@ -275,21 +283,23 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
     .overrides(fmt_override)
     .build_parallel();
 
-    // there is a lot of blocking involved in spawning a child process and reading files to format.
-    // spawn more processes than available concurrency to keep the CPU busy
+    // There is a lot of blocking involved in spawning a child process and reading files to format.
+    // Spawn more processes than available concurrency to keep the CPU busy.
     let max_processes = build.jobs() as usize * 2;
 
-    // spawn child processes on a separate thread so we can batch entries we have received from ignore
+    // Spawn child processes on a separate thread so we can batch entries we have received from
+    // ignore.
     let thread = std::thread::spawn(move || {
         let mut children = VecDeque::new();
         while let Ok(path) = rx.recv() {
-            // try getting more paths from the channel to amortize the overhead of spawning processes
+            // Try getting more paths from the channel to amortize the overhead of spawning
+            // processes.
             let paths: Vec<_> = rx.try_iter().take(63).chain(std::iter::once(path)).collect();
 
             let child = rustfmt(&src, &rustfmt_path, paths.as_slice(), check);
             children.push_back(child);
 
-            // poll completion before waiting
+            // Poll completion before waiting.
             for i in (0..children.len()).rev() {
                 if children[i](false) {
                     children.swap_remove_back(i);
@@ -298,12 +308,12 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
             }
 
             if children.len() >= max_processes {
-                // await oldest child
+                // Await oldest child.
                 children.pop_front().unwrap()(true);
             }
         }
 
-        // await remaining children
+        // Await remaining children.
         for mut child in children {
             child(true);
         }
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 05470eebf01..ca86f3f0110 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -378,7 +378,6 @@ auto:
       # We are intentionally allowing an old toolchain on this builder (and that's
       # incompatible with LLVM downloads today).
       NO_DOWNLOAD_CI_LLVM: 1
-      CUSTOM_MINGW: 1
     <<: *job-windows-8c
 
   - image: x86_64-mingw
@@ -390,7 +389,6 @@ auto:
       # We are intentionally allowing an old toolchain on this builder (and that's
       # incompatible with LLVM downloads today).
       NO_DOWNLOAD_CI_LLVM: 1
-      CUSTOM_MINGW: 1
     <<: *job-windows-8c
 
   - image: dist-x86_64-msvc
@@ -439,7 +437,6 @@ auto:
       # incompatible with LLVM downloads today).
       NO_DOWNLOAD_CI_LLVM: 1
       SCRIPT: python x.py dist bootstrap --include-default-paths
-      CUSTOM_MINGW: 1
       DIST_REQUIRE_ALL_TOOLS: 1
     <<: *job-windows-8c
 
@@ -453,7 +450,6 @@ auto:
       # We are intentionally allowing an old toolchain on this builder (and that's
       # incompatible with LLVM downloads today).
       NO_DOWNLOAD_CI_LLVM: 1
-      CUSTOM_MINGW: 1
       DIST_REQUIRE_ALL_TOOLS: 1
     <<: *job-windows-8c
 
diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh
index 45541b8b693..31aa3785bc3 100755
--- a/src/ci/scripts/install-mingw.sh
+++ b/src/ci/scripts/install-mingw.sh
@@ -1,8 +1,5 @@
 #!/bin/bash
-# If we need to download a custom MinGW, do so here and set the path
-# appropriately.
-#
-# Otherwise install MinGW through `pacman`
+# For mingw builds use a vendored mingw.
 
 set -euo pipefail
 IFS=$'\n\t'
@@ -16,19 +13,16 @@ if isWindows && isKnownToBeMingwBuild; then
     case "${CI_JOB_NAME}" in
         *i686*)
             bits=32
-            arch=i686
             mingw_archive="${MINGW_ARCHIVE_32}"
             ;;
         *x86_64*)
             bits=64
-            arch=x86_64
             mingw_archive="${MINGW_ARCHIVE_64}"
             ;;
         *aarch64*)
             # aarch64 is a cross-compiled target. Use the x86_64
             # mingw, since that's the host architecture.
             bits=64
-            arch=x86_64
             mingw_archive="${MINGW_ARCHIVE_64}"
             ;;
         *)
@@ -38,13 +32,9 @@ if isWindows && isKnownToBeMingwBuild; then
             ;;
     esac
 
-    if [[ "${CUSTOM_MINGW:-0}" == 0 ]]; then
-        pacman -S --noconfirm --needed mingw-w64-$arch-toolchain
-    else
-        mingw_dir="mingw${bits}"
+    mingw_dir="mingw${bits}"
 
-        curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}"
-        7z x -y mingw.7z > /dev/null
-        ciCommandAddPath "$(pwd)/${mingw_dir}/bin"
-    fi
+    curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}"
+    7z x -y mingw.7z > /dev/null
+    ciCommandAddPath "$(pwd)/${mingw_dir}/bin"
 fi
diff --git a/src/ci/scripts/install-msys2.sh b/src/ci/scripts/install-msys2.sh
deleted file mode 100755
index 968b1e572e4..00000000000
--- a/src/ci/scripts/install-msys2.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/bash
-# Clean up and prepare the MSYS2 installation.
-# MSYS2 is used by the MinGW toolchain for assembling things.
-
-set -euo pipefail
-IFS=$'\n\t'
-
-source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
-if isWindows; then
-    # Detect the native Python version installed on the agent. On GitHub
-    # Actions, the C:\hostedtoolcache\windows\Python directory contains a
-    # subdirectory for each installed Python version.
-    #
-    # The -V flag of the sort command sorts the input by version number.
-    native_python_version="$(ls /c/hostedtoolcache/windows/Python | sort -Vr | head -n 1)"
-
-    # Make sure we use the native python interpreter instead of some msys equivalent
-    # one way or another. The msys interpreters seem to have weird path conversions
-    # baked in which break LLVM's build system one way or another, so let's use the
-    # native version which keeps everything as native as possible.
-    python_home="/c/hostedtoolcache/windows/Python/${native_python_version}/x64"
-    if ! [[ -f "${python_home}/python3.exe" ]]; then
-        cp "${python_home}/python.exe" "${python_home}/python3.exe"
-    fi
-    ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64"
-    ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64\\Scripts"
-fi
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index d96c8b89127..35d7b65bec0 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -268,6 +268,17 @@ pub fn recursive_diff(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) {
     }
 }
 
+/// Check that `haystack` does not contain `needle`. Panic otherwise.
+pub fn assert_not_contains(haystack: &str, needle: &str) {
+    if haystack.contains(needle) {
+        eprintln!("=== HAYSTACK ===");
+        eprintln!("{}", haystack);
+        eprintln!("=== NEEDLE ===");
+        eprintln!("{}", needle);
+        panic!("needle was unexpectedly found in haystack");
+    }
+}
+
 /// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
 /// containing a `cmd: Command` field and a `output` function. The provided helpers are:
 ///
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 2329b8b44de..9ca27834cf7 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -1,6 +1,5 @@
 run-make/allocator-shim-circular-deps/Makefile
 run-make/allow-non-lint-warnings-cmdline/Makefile
-run-make/allow-warnings-cmdline-stability/Makefile
 run-make/archive-duplicate-names/Makefile
 run-make/atomic-lock-free/Makefile
 run-make/bare-outfile/Makefile
diff --git a/tests/assembly/nvptx-c-abi-arg-v7.rs b/tests/assembly/nvptx-c-abi-arg-v7.rs
new file mode 100644
index 00000000000..99f90ea526e
--- /dev/null
+++ b/tests/assembly/nvptx-c-abi-arg-v7.rs
@@ -0,0 +1,206 @@
+//@ assembly-output: ptx-linker
+//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc
+//@ only-nvptx64
+
+// The PTX ABI stability is tied to major versions of the PTX ISA
+// These tests assume major version 7
+
+// CHECK: .version 7
+
+#![feature(abi_ptx, lang_items, no_core)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+#[repr(C)]
+pub struct SingleU8 {
+    f: u8,
+}
+
+#[repr(C)]
+pub struct DoubleU8 {
+    f: u8,
+    g: u8,
+}
+
+#[repr(C)]
+pub struct TripleU8 {
+    f: u8,
+    g: u8,
+    h: u8,
+}
+
+#[repr(C)]
+pub struct TripleU16 {
+    f: u16,
+    g: u16,
+    h: u16,
+}
+#[repr(C)]
+pub struct TripleU32 {
+    f: u32,
+    g: u32,
+    h: u32,
+}
+#[repr(C)]
+pub struct TripleU64 {
+    f: u64,
+    g: u64,
+    h: u64,
+}
+
+#[repr(C)]
+pub struct DoubleFloat {
+    f: f32,
+    g: f32,
+}
+
+#[repr(C)]
+pub struct TripleFloat {
+    f: f32,
+    g: f32,
+    h: f32,
+}
+
+#[repr(C)]
+pub struct TripleDouble {
+    f: f64,
+    g: f64,
+    h: f64,
+}
+
+#[repr(C)]
+pub struct ManyIntegers {
+    f: u8,
+    g: u16,
+    h: u32,
+    i: u64,
+}
+
+#[repr(C)]
+pub struct ManyNumerics {
+    f: u8,
+    g: u16,
+    h: u32,
+    i: u64,
+    j: f32,
+    k: f64,
+}
+
+// CHECK: .visible .func f_u8_arg(
+// CHECK: .param .b32 f_u8_arg_param_0
+#[no_mangle]
+pub unsafe extern "C" fn f_u8_arg(_a: u8) {}
+
+// CHECK: .visible .func f_u16_arg(
+// CHECK: .param .b32 f_u16_arg_param_0
+#[no_mangle]
+pub unsafe extern "C" fn f_u16_arg(_a: u16) {}
+
+// CHECK: .visible .func f_u32_arg(
+// CHECK: .param .b32 f_u32_arg_param_0
+#[no_mangle]
+pub unsafe extern "C" fn f_u32_arg(_a: u32) {}
+
+// CHECK: .visible .func f_u64_arg(
+// CHECK: .param .b64 f_u64_arg_param_0
+#[no_mangle]
+pub unsafe extern "C" fn f_u64_arg(_a: u64) {}
+
+// CHECK: .visible .func f_u128_arg(
+// CHECK: .param .align 16 .b8 f_u128_arg_param_0[16]
+#[no_mangle]
+pub unsafe extern "C" fn f_u128_arg(_a: u128) {}
+
+// CHECK: .visible .func f_i8_arg(
+// CHECK: .param .b32 f_i8_arg_param_0
+#[no_mangle]
+pub unsafe extern "C" fn f_i8_arg(_a: i8) {}
+
+// CHECK: .visible .func f_i16_arg(
+// CHECK: .param .b32 f_i16_arg_param_0
+#[no_mangle]
+pub unsafe extern "C" fn f_i16_arg(_a: i16) {}
+
+// CHECK: .visible .func f_i32_arg(
+// CHECK: .param .b32 f_i32_arg_param_0
+#[no_mangle]
+pub unsafe extern "C" fn f_i32_arg(_a: i32) {}
+
+// CHECK: .visible .func f_i64_arg(
+// CHECK: .param .b64 f_i64_arg_param_0
+#[no_mangle]
+pub unsafe extern "C" fn f_i64_arg(_a: i64) {}
+
+// CHECK: .visible .func f_i128_arg(
+// CHECK: .param .align 16 .b8 f_i128_arg_param_0[16]
+#[no_mangle]
+pub unsafe extern "C" fn f_i128_arg(_a: i128) {}
+
+// CHECK: .visible .func f_f32_arg(
+// CHECK: .param .b32 f_f32_arg_param_0
+#[no_mangle]
+pub unsafe extern "C" fn f_f32_arg(_a: f32) {}
+
+// CHECK: .visible .func f_f64_arg(
+// CHECK: .param .b64 f_f64_arg_param_0
+#[no_mangle]
+pub unsafe extern "C" fn f_f64_arg(_a: f64) {}
+
+// CHECK: .visible .func f_single_u8_arg(
+// CHECK: .param .align 1 .b8 f_single_u8_arg_param_0[1]
+#[no_mangle]
+pub unsafe extern "C" fn f_single_u8_arg(_a: SingleU8) {}
+
+// CHECK: .visible .func f_double_u8_arg(
+// CHECK: .param .align 1 .b8 f_double_u8_arg_param_0[2]
+#[no_mangle]
+pub unsafe extern "C" fn f_double_u8_arg(_a: DoubleU8) {}
+
+// CHECK: .visible .func f_triple_u8_arg(
+// CHECK: .param .align 1 .b8 f_triple_u8_arg_param_0[3]
+#[no_mangle]
+pub unsafe extern "C" fn f_triple_u8_arg(_a: TripleU8) {}
+
+// CHECK: .visible .func f_triple_u16_arg(
+// CHECK: .param .align 2 .b8 f_triple_u16_arg_param_0[6]
+#[no_mangle]
+pub unsafe extern "C" fn f_triple_u16_arg(_a: TripleU16) {}
+
+// CHECK: .visible .func f_triple_u32_arg(
+// CHECK: .param .align 4 .b8 f_triple_u32_arg_param_0[12]
+#[no_mangle]
+pub unsafe extern "C" fn f_triple_u32_arg(_a: TripleU32) {}
+
+// CHECK: .visible .func f_triple_u64_arg(
+// CHECK: .param .align 8 .b8 f_triple_u64_arg_param_0[24]
+#[no_mangle]
+pub unsafe extern "C" fn f_triple_u64_arg(_a: TripleU64) {}
+
+// CHECK: .visible .func f_many_integers_arg(
+// CHECK: .param .align 8 .b8 f_many_integers_arg_param_0[16]
+#[no_mangle]
+pub unsafe extern "C" fn f_many_integers_arg(_a: ManyIntegers) {}
+
+// CHECK: .visible .func f_double_float_arg(
+// CHECK: .param .align 4 .b8 f_double_float_arg_param_0[8]
+#[no_mangle]
+pub unsafe extern "C" fn f_double_float_arg(_a: DoubleFloat) {}
+
+// CHECK: .visible .func f_triple_float_arg(
+// CHECK: .param .align 4 .b8 f_triple_float_arg_param_0[12]
+#[no_mangle]
+pub unsafe extern "C" fn f_triple_float_arg(_a: TripleFloat) {}
+
+// CHECK: .visible .func f_triple_double_arg(
+// CHECK: .param .align 8 .b8 f_triple_double_arg_param_0[24]
+#[no_mangle]
+pub unsafe extern "C" fn f_triple_double_arg(_a: TripleDouble) {}
+
+// CHECK: .visible .func f_many_numerics_arg(
+// CHECK: .param .align 8 .b8 f_many_numerics_arg_param_0[32]
+#[no_mangle]
+pub unsafe extern "C" fn f_many_numerics_arg(_a: ManyNumerics) {}
diff --git a/tests/assembly/nvptx-c-abi-ret-v7.rs b/tests/assembly/nvptx-c-abi-ret-v7.rs
new file mode 100644
index 00000000000..0c1594a5f20
--- /dev/null
+++ b/tests/assembly/nvptx-c-abi-ret-v7.rs
@@ -0,0 +1,230 @@
+//@ assembly-output: ptx-linker
+//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc
+//@ only-nvptx64
+//@ ignore-nvptx64
+
+// The PTX ABI stability is tied to major versions of the PTX ISA
+// These tests assume major version 7
+
+// CHECK: .version 7
+
+#![feature(abi_ptx, lang_items, no_core)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+#[repr(C)]
+pub struct SingleU8 {
+    f: u8,
+}
+
+#[repr(C)]
+pub struct DoubleU8 {
+    f: u8,
+    g: u8,
+}
+
+#[repr(C)]
+pub struct TripleU8 {
+    f: u8,
+    g: u8,
+    h: u8,
+}
+
+#[repr(C)]
+pub struct TripleU16 {
+    f: u16,
+    g: u16,
+    h: u16,
+}
+#[repr(C)]
+pub struct TripleU32 {
+    f: u32,
+    g: u32,
+    h: u32,
+}
+#[repr(C)]
+pub struct TripleU64 {
+    f: u64,
+    g: u64,
+    h: u64,
+}
+
+#[repr(C)]
+pub struct DoubleFloat {
+    f: f32,
+    g: f32,
+}
+
+#[repr(C)]
+pub struct TripleFloat {
+    f: f32,
+    g: f32,
+    h: f32,
+}
+
+#[repr(C)]
+pub struct TripleDouble {
+    f: f64,
+    g: f64,
+    h: f64,
+}
+
+#[repr(C)]
+pub struct ManyIntegers {
+    f: u8,
+    g: u16,
+    h: u32,
+    i: u64,
+}
+
+#[repr(C)]
+pub struct ManyNumerics {
+    f: u8,
+    g: u16,
+    h: u32,
+    i: u64,
+    j: f32,
+    k: f64,
+}
+
+// CHECK: .visible .func (.param .b32 func_retval0) f_u8_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_u8_ret() -> u8 {
+    0
+}
+
+// CHECK: .visible .func (.param .b32 func_retval0) f_u16_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_u16_ret() -> u16 {
+    1
+}
+
+// CHECK: .visible .func (.param .b32 func_retval0) f_u32_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_u32_ret() -> u32 {
+    2
+}
+
+// CHECK: .visible .func (.param .b64 func_retval0) f_u64_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_u64_ret() -> u64 {
+    3
+}
+
+// CHECK: .visible .func (.param .align 16 .b8 func_retval0[16]) f_u128_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_u128_ret() -> u128 {
+    4
+}
+
+// CHECK: .visible .func (.param .b32 func_retval0) f_i8_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_i8_ret() -> i8 {
+    5
+}
+
+// CHECK: .visible .func (.param .b32 func_retval0) f_i16_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_i16_ret() -> i16 {
+    6
+}
+
+// CHECK: .visible .func (.param .b32 func_retval0) f_i32_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_i32_ret() -> i32 {
+    7
+}
+
+// CHECK: .visible .func (.param .b64 func_retval0) f_i64_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_i64_ret() -> i64 {
+    8
+}
+
+// CHECK: .visible .func  (.param .align 16 .b8 func_retval0[16]) f_i128_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_i128_ret() -> i128 {
+    9
+}
+
+// CHECK: .visible .func (.param .b32 func_retval0) f_f32_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_f32_ret() -> f32 {
+    10.0
+}
+
+// CHECK: .visible .func (.param .b64 func_retval0) f_f64_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_f64_ret() -> f64 {
+    11.0
+}
+
+// CHECK: .visible .func (.param .align 1 .b8 func_retval0[1]) f_single_u8_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_single_u8_ret() -> SingleU8 {
+    SingleU8 { f: 12 }
+}
+
+// CHECK: .visible .func (.param .align 1 .b8 func_retval0[2]) f_double_u8_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_double_u8_ret() -> DoubleU8 {
+    DoubleU8 { f: 13, g: 14 }
+}
+
+// CHECK: .visible .func (.param .align 1 .b8 func_retval0[3]) f_triple_u8_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_triple_u8_ret() -> TripleU8 {
+    TripleU8 { f: 15, g: 16, h: 17 }
+}
+
+// CHECK: .visible .func (.param .align 2 .b8 func_retval0[6]) f_triple_u16_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_triple_u16_ret() -> TripleU16 {
+    TripleU16 { f: 18, g: 19, h: 20 }
+}
+
+// CHECK: .visible .func (.param .align 4 .b8 func_retval0[12]) f_triple_u32_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_triple_u32_ret() -> TripleU32 {
+    TripleU32 { f: 20, g: 21, h: 22 }
+}
+
+// CHECK: .visible .func (.param .align 8 .b8 func_retval0[24]) f_triple_u64_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_triple_u64_ret() -> TripleU64 {
+    TripleU64 { f: 23, g: 24, h: 25 }
+}
+
+// CHECK: .visible .func (.param .align 8 .b8 func_retval0[16]) f_many_integers_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_many_integers_ret() -> ManyIntegers {
+    ManyIntegers { f: 26, g: 27, h: 28, i: 29 }
+}
+
+// CHECK: .visible .func (.param .align 4 .b8 func_retval0[8]) f_double_float_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_double_float_ret() -> DoubleFloat {
+    DoubleFloat { f: 29.0, g: 30.0 }
+}
+
+// CHECK: .visible .func (.param .align 4 .b8 func_retval0[12]) f_triple_float_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_triple_float_ret() -> TripleFloat {
+    TripleFloat { f: 31.0, g: 32.0, h: 33.0 }
+}
+
+// CHECK: .visible .func (.param .align 8 .b8 func_retval0[24]) f_triple_double_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_triple_double_ret() -> TripleDouble {
+    TripleDouble { f: 34.0, g: 35.0, h: 36.0 }
+}
+
+// CHECK: .visible .func (.param .align 8 .b8 func_retval0[32]) f_many_numerics_ret(
+#[no_mangle]
+pub unsafe extern "C" fn f_many_numerics_ret() -> ManyNumerics {
+    ManyNumerics { f: 37, g: 38, h: 39, i: 40, j: 41.0, k: 43.0 }
+}
diff --git a/tests/run-make/allow-warnings-cmdline-stability/Makefile b/tests/run-make/allow-warnings-cmdline-stability/Makefile
deleted file mode 100644
index 368a39af6bf..00000000000
--- a/tests/run-make/allow-warnings-cmdline-stability/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-# Test that -A warnings makes the 'empty trait list for derive' warning go away
-DEP=$(shell $(RUSTC) bar.rs)
-OUT=$(shell $(RUSTC) foo.rs -A warnings 2>&1 | grep "warning" )
-
-all: foo bar
-	test -z '$(OUT)'
-
-# These are just to ensure that the above commands actually work
-bar:
-	$(RUSTC) bar.rs
-
-foo: bar
-	$(RUSTC) foo.rs -A warnings
diff --git a/tests/run-make/allow-warnings-cmdline-stability/rmake.rs b/tests/run-make/allow-warnings-cmdline-stability/rmake.rs
new file mode 100644
index 00000000000..8f6fe6bd0b6
--- /dev/null
+++ b/tests/run-make/allow-warnings-cmdline-stability/rmake.rs
@@ -0,0 +1,11 @@
+// Test that `-Awarnings` suppresses warnings for unstable APIs.
+
+use run_make_support::{assert_not_contains, rustc};
+
+fn main() {
+    rustc().input("bar.rs").run();
+    let output = rustc().input("foo.rs").arg("-Awarnings").run();
+
+    assert_not_contains(&String::from_utf8(output.stdout).unwrap(), "warning");
+    assert_not_contains(&String::from_utf8(output.stderr).unwrap(), "warning");
+}