about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/lib.rs35
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs23
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs92
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/mod.rs38
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs4
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs16
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs4
-rw-r--r--compiler/rustc_const_eval/src/check_consts/qualifs.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs6
-rw-r--r--compiler/rustc_const_eval/src/util/compare_types.rs5
-rw-r--r--compiler/rustc_expand/messages.ftl2
-rw-r--r--compiler/rustc_expand/src/errors.rs2
-rw-r--r--compiler/rustc_expand/src/expand.rs5
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs13
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs5
-rw-r--r--compiler/rustc_infer/src/infer/at.rs36
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs6
-rw-r--r--compiler/rustc_infer/src/infer/context.rs17
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs99
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/mod.rs49
-rw-r--r--compiler/rustc_infer/src/infer/relate/generalize.rs11
-rw-r--r--compiler/rustc_lint/src/builtin.rs8
-rw-r--r--compiler/rustc_lint/src/context.rs12
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs2
-rw-r--r--compiler/rustc_lint/src/impl_trait_overcaptures.rs4
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs2
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp6
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp78
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs18
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs10
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs25
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs109
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/results.rs (renamed from compiler/rustc_mir_dataflow/src/framework/engine.rs)121
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs15
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs23
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs3
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs5
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs8
-rw-r--r--compiler/rustc_mir_transform/src/lint.rs6
-rw-r--r--compiler/rustc_mir_transform/src/ref_prop.rs3
-rw-r--r--compiler/rustc_mir_transform/src/remove_uninit_drops.rs4
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/delegate.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs14
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs3
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs23
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs17
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs50
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs46
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs4
-rw-r--r--compiler/rustc_passes/src/layout_test.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/effects.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs36
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs93
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs5
-rw-r--r--compiler/rustc_traits/src/codegen.rs4
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs4
-rw-r--r--compiler/rustc_ty_utils/src/common_traits.rs4
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs4
-rw-r--r--compiler/rustc_ty_utils/src/structural_match.rs4
-rw-r--r--compiler/rustc_type_ir/src/canonical.rs4
-rw-r--r--compiler/rustc_type_ir/src/infer_ctxt.rs68
-rw-r--r--compiler/rustc_type_ir/src/interner.rs23
-rw-r--r--compiler/rustc_type_ir/src/relate/combine.rs18
-rw-r--r--compiler/rustc_type_ir/src/search_graph/mod.rs21
-rw-r--r--compiler/rustc_type_ir/src/solve/mod.rs13
-rw-r--r--src/doc/rustc/src/platform-support/aix.md4
-rw-r--r--src/doc/rustc/src/platform-support/fuchsia.md12
-rw-r--r--src/librustdoc/clean/blanket_impl.rs4
-rw-r--r--src/librustdoc/clean/mod.rs6
-rw-r--r--src/librustdoc/html/format.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs10
-rw-r--r--tests/ui/array-slice-vec/vec-macro-with-comma-only.rs2
-rw-r--r--tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr2
-rw-r--r--tests/ui/editions/edition-keywords-2015-2015-parsing.rs4
-rw-r--r--tests/ui/editions/edition-keywords-2015-2015-parsing.stderr4
-rw-r--r--tests/ui/editions/edition-keywords-2015-2018-parsing.rs4
-rw-r--r--tests/ui/editions/edition-keywords-2015-2018-parsing.stderr4
-rw-r--r--tests/ui/editions/edition-keywords-2018-2015-parsing.rs4
-rw-r--r--tests/ui/editions/edition-keywords-2018-2015-parsing.stderr6
-rw-r--r--tests/ui/editions/edition-keywords-2018-2018-parsing.rs4
-rw-r--r--tests/ui/editions/edition-keywords-2018-2018-parsing.stderr6
-rw-r--r--tests/ui/fail-simple.rs2
-rw-r--r--tests/ui/fail-simple.stderr2
-rw-r--r--tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr4
-rw-r--r--tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr4
-rw-r--r--tests/ui/macros/best-failure.rs2
-rw-r--r--tests/ui/macros/best-failure.stderr2
-rw-r--r--tests/ui/macros/expr_2021_inline_const.edi2021.stderr4
-rw-r--r--tests/ui/macros/expr_2021_inline_const.edi2024.stderr2
-rw-r--r--tests/ui/macros/expr_2021_inline_const.rs4
-rw-r--r--tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr4
-rw-r--r--tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr2
-rw-r--r--tests/ui/macros/expr_2024_underscore_expr.rs4
-rw-r--r--tests/ui/macros/issue-118786.rs2
-rw-r--r--tests/ui/macros/issue-118786.stderr2
-rw-r--r--tests/ui/macros/issue-30007.rs2
-rw-r--r--tests/ui/macros/issue-30007.stderr2
-rw-r--r--tests/ui/macros/issue-54441.rs2
-rw-r--r--tests/ui/macros/issue-54441.stderr2
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2015.rs14
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2015.stderr14
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2018.rs14
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2018.stderr14
-rw-r--r--tests/ui/macros/macro-context.rs6
-rw-r--r--tests/ui/macros/macro-context.stderr6
-rw-r--r--tests/ui/macros/macro-in-expression-context.fixed2
-rw-r--r--tests/ui/macros/macro-in-expression-context.rs2
-rw-r--r--tests/ui/macros/macro-in-expression-context.stderr2
-rw-r--r--tests/ui/macros/macro-non-lifetime.rs2
-rw-r--r--tests/ui/macros/macro-non-lifetime.stderr2
-rw-r--r--tests/ui/macros/missing-comma.rs10
-rw-r--r--tests/ui/macros/missing-comma.stderr10
-rw-r--r--tests/ui/macros/nonterminal-matching.rs10
-rw-r--r--tests/ui/macros/nonterminal-matching.stderr14
-rw-r--r--tests/ui/macros/syntax-error-recovery.rs2
-rw-r--r--tests/ui/macros/syntax-error-recovery.stderr2
-rw-r--r--tests/ui/macros/trace_faulty_macros.stderr2
-rw-r--r--tests/ui/offset-of/offset-of-arg-count.rs2
-rw-r--r--tests/ui/offset-of/offset-of-arg-count.stderr2
-rw-r--r--tests/ui/offset-of/offset-of-tuple.stderr2
-rw-r--r--tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs4
-rw-r--r--tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr4
-rw-r--r--tests/ui/parser/macro/macro-doc-comments-1.rs2
-rw-r--r--tests/ui/parser/macro/macro-doc-comments-1.stderr2
-rw-r--r--tests/ui/parser/macro/macro-doc-comments-2.rs2
-rw-r--r--tests/ui/parser/macro/macro-doc-comments-2.stderr2
-rw-r--r--tests/ui/parser/macro/macro-expand-to-match-arm.rs2
-rw-r--r--tests/ui/parser/macro/macro-expand-to-match-arm.stderr2
-rw-r--r--tests/ui/parser/macro/macro-incomplete-parse.rs4
-rw-r--r--tests/ui/parser/macro/macro-incomplete-parse.stderr4
-rw-r--r--tests/ui/parser/macro/trait-non-item-macros.rs2
-rw-r--r--tests/ui/parser/macro/trait-non-item-macros.stderr2
-rw-r--r--tests/ui/proc-macro/attr-invalid-exprs.rs4
-rw-r--r--tests/ui/proc-macro/attr-invalid-exprs.stderr4
-rw-r--r--tests/ui/proc-macro/expand-expr.rs4
-rw-r--r--tests/ui/proc-macro/expand-expr.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs2
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs2
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr20
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs20
-rw-r--r--tests/ui/underscore-ident-matcher.rs2
-rw-r--r--tests/ui/underscore-ident-matcher.stderr2
195 files changed, 1009 insertions, 1071 deletions
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 698fdafc936..efcee2899c6 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -34,7 +34,7 @@ use rustc_infer::infer::{
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt};
+use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use rustc_mir_dataflow::Analysis;
 use rustc_mir_dataflow::impls::{
@@ -193,9 +193,7 @@ fn do_mir_borrowck<'tcx>(
         .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true)));
 
     let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
-        .into_engine(tcx, body)
-        .pass_name("borrowck")
-        .iterate_to_fixpoint()
+        .iterate_to_fixpoint(tcx, body, Some("borrowck"))
         .into_results_cursor(body);
 
     let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure();
@@ -243,18 +241,21 @@ fn do_mir_borrowck<'tcx>(
     // usage significantly on some benchmarks.
     drop(flow_inits);
 
-    let flow_borrows = Borrows::new(tcx, body, &regioncx, &borrow_set)
-        .into_engine(tcx, body)
-        .pass_name("borrowck")
-        .iterate_to_fixpoint();
-    let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
-        .into_engine(tcx, body)
-        .pass_name("borrowck")
-        .iterate_to_fixpoint();
-    let flow_ever_inits = EverInitializedPlaces::new(body, &move_data)
-        .into_engine(tcx, body)
-        .pass_name("borrowck")
-        .iterate_to_fixpoint();
+    let flow_borrows = Borrows::new(tcx, body, &regioncx, &borrow_set).iterate_to_fixpoint(
+        tcx,
+        body,
+        Some("borrowck"),
+    );
+    let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(
+        tcx,
+        body,
+        Some("borrowck"),
+    );
+    let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(
+        tcx,
+        body,
+        Some("borrowck"),
+    );
 
     let movable_coroutine =
         // The first argument is the coroutine type passed by value
@@ -440,7 +441,7 @@ pub struct BorrowckInferCtxt<'tcx> {
 
 impl<'tcx> BorrowckInferCtxt<'tcx> {
     pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
-        let infcx = tcx.infer_ctxt().with_opaque_type_inference(def_id).build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id));
         BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) }
     }
 
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index abce98265b3..741dac9e763 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -9,6 +9,7 @@ use rustc_macros::extension;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{
     self, GenericArgKind, GenericArgs, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
+    TypingMode,
 };
 use rustc_span::Span;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@@ -340,14 +341,13 @@ fn check_opaque_type_well_formed<'tcx>(
         parent_def_id = tcx.local_parent(parent_def_id);
     }
 
-    // FIXME(-Znext-solver): We probably should use `&[]` instead of
-    // and prepopulate this `InferCtxt` with known opaque values, rather than
-    // allowing opaque types to be defined and checking them after the fact.
+    // FIXME(#132279): This should eventually use the already defined hidden types
+    // instead. Alternatively we'll entirely remove this function given we also check
+    // the opaque in `check_opaque_meets_bounds` later.
     let infcx = tcx
         .infer_ctxt()
         .with_next_trait_solver(next_trait_solver)
-        .with_opaque_type_inference(parent_def_id)
-        .build();
+        .build(TypingMode::analysis_in_body(tcx, parent_def_id));
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
     let identity_args = GenericArgs::identity_for_item(tcx, def_id);
 
@@ -517,7 +517,9 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
             },
         );
 
-        let infcx = tcx.infer_ctxt().build();
+        // FIXME(#132279): It feels wrong to use `non_body_analysis` here given that we're
+        // in a body here.
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let ocx = ObligationCtxt::new(&infcx);
 
         let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| {
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index a2e6c7eb856..149ded28356 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -154,7 +154,7 @@ fn create_wrapper_function(
             .enumerate()
             .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
             .collect::<Vec<_>>();
-        let ret = llvm::LLVMRustBuildCall(
+        let ret = llvm::LLVMBuildCallWithOperandBundles(
             llbuilder,
             ty,
             callee,
@@ -162,6 +162,7 @@ fn create_wrapper_function(
             args.len() as c_uint,
             [].as_ptr(),
             0 as c_uint,
+            c"".as_ptr(),
         );
         llvm::LLVMSetTailCall(ret, True);
         if output.is_some() {
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 02149e176ea..48beb9be2b2 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -165,13 +165,14 @@ fn get_bitcode_slice_from_object_data<'a>(
     // We drop the "__LLVM," prefix here because on Apple platforms there's a notion of "segment
     // name" which in the public API for sections gets treated as part of the section name, but
     // internally in MachOObjectFile.cpp gets treated separately.
-    let section_name = bitcode_section_name(cgcx).trim_start_matches("__LLVM,");
+    let section_name = bitcode_section_name(cgcx).to_str().unwrap().trim_start_matches("__LLVM,");
     let mut len = 0;
     let data = unsafe {
         llvm::LLVMRustGetSliceFromObjectDataByName(
             obj.as_ptr(),
             obj.len(),
             section_name.as_ptr(),
+            section_name.len(),
             &mut len,
         )
     };
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index e68ba96f14f..bfa9e8b82a0 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -1,4 +1,4 @@
-use std::ffi::CString;
+use std::ffi::{CStr, CString};
 use std::io::{self, Write};
 use std::path::{Path, PathBuf};
 use std::sync::Arc;
@@ -958,14 +958,13 @@ fn target_is_aix(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool {
     cgcx.opts.target_triple.triple().contains("-aix")
 }
 
-//FIXME use c string literals here too
-pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static str {
+pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static CStr {
     if target_is_apple(cgcx) {
-        "__LLVM,__bitcode\0"
+        c"__LLVM,__bitcode"
     } else if target_is_aix(cgcx) {
-        ".ipa\0"
+        c".ipa"
     } else {
-        ".llvmbc\0"
+        c".llvmbc"
     }
 }
 
@@ -1042,8 +1041,7 @@ unsafe fn embed_bitcode(
             );
             llvm::LLVMSetInitializer(llglobal, llconst);
 
-            let section = bitcode_section_name(cgcx);
-            llvm::LLVMSetSection(llglobal, section.as_c_char_ptr());
+            llvm::set_section(llglobal, bitcode_section_name(cgcx));
             llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
             llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
 
@@ -1061,7 +1059,7 @@ unsafe fn embed_bitcode(
             } else {
                 c".llvmcmd"
             };
-            llvm::LLVMSetSection(llglobal, section.as_ptr());
+            llvm::set_section(llglobal, section);
             llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
         } else {
             // We need custom section flags, so emit module-level inline assembly.
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 0ba8d82406a..32793894794 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -145,10 +145,8 @@ pub(crate) fn compile_codegen_unit(
 
 pub(crate) fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
     let Some(sect) = attrs.link_section else { return };
-    unsafe {
-        let buf = SmallCStr::new(sect.as_str());
-        llvm::LLVMSetSection(llval, buf.as_ptr());
-    }
+    let buf = SmallCStr::new(sect.as_str());
+    llvm::set_section(llval, &buf);
 }
 
 pub(crate) fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage {
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 8702532c36e..f8eb3e0c982 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -239,7 +239,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
 
         let args = self.check_call("invoke", llty, llfn, args);
         let funclet_bundle = funclet.map(|funclet| funclet.bundle());
-        let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
         let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
         if let Some(funclet_bundle) = funclet_bundle {
             bundles.push(funclet_bundle);
@@ -250,13 +249,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
 
         // Emit KCFI operand bundle
         let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
-        let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
-        if let Some(kcfi_bundle) = kcfi_bundle {
+        if let Some(kcfi_bundle) = kcfi_bundle.as_deref() {
             bundles.push(kcfi_bundle);
         }
 
         let invoke = unsafe {
-            llvm::LLVMRustBuildInvoke(
+            llvm::LLVMBuildInvokeWithOperandBundles(
                 self.llbuilder,
                 llty,
                 llfn,
@@ -1179,7 +1177,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
 
         let args = self.check_call("call", llty, llfn, args);
         let funclet_bundle = funclet.map(|funclet| funclet.bundle());
-        let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
         let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
         if let Some(funclet_bundle) = funclet_bundle {
             bundles.push(funclet_bundle);
@@ -1190,13 +1187,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
 
         // Emit KCFI operand bundle
         let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
-        let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
-        if let Some(kcfi_bundle) = kcfi_bundle {
+        if let Some(kcfi_bundle) = kcfi_bundle.as_deref() {
             bundles.push(kcfi_bundle);
         }
 
         let call = unsafe {
-            llvm::LLVMRustBuildCall(
+            llvm::LLVMBuildCallWithOperandBundles(
                 self.llbuilder,
                 llty,
                 llfn,
@@ -1204,6 +1200,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 args.len() as c_uint,
                 bundles.as_ptr(),
                 bundles.len() as c_uint,
+                c"".as_ptr(),
             )
         };
         if let Some(fn_abi) = fn_abi {
@@ -1509,7 +1506,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
 
         let args = self.check_call("callbr", llty, llfn, args);
         let funclet_bundle = funclet.map(|funclet| funclet.bundle());
-        let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
         let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
         if let Some(funclet_bundle) = funclet_bundle {
             bundles.push(funclet_bundle);
@@ -1520,13 +1516,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
 
         // Emit KCFI operand bundle
         let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
-        let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
-        if let Some(kcfi_bundle) = kcfi_bundle {
+        if let Some(kcfi_bundle) = kcfi_bundle.as_deref() {
             bundles.push(kcfi_bundle);
         }
 
         let callbr = unsafe {
-            llvm::LLVMRustBuildCallBr(
+            llvm::LLVMBuildCallBr(
                 self.llbuilder,
                 llty,
                 llfn,
@@ -1601,7 +1596,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
         instance: Option<Instance<'tcx>>,
         llfn: &'ll Value,
-    ) -> Option<llvm::OperandBundleDef<'ll>> {
+    ) -> Option<llvm::OperandBundleOwned<'ll>> {
         let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
         let kcfi_bundle = if self.tcx.sess.is_sanitizer_kcfi_enabled()
             && let Some(fn_abi) = fn_abi
@@ -1627,7 +1622,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
                 kcfi::typeid_for_fnabi(self.tcx, fn_abi, options)
             };
 
-            Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
+            Some(llvm::OperandBundleOwned::new("kcfi", &[self.const_u32(kcfi_typeid)]))
         } else {
             None
         };
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 29adc616ee2..8852dec7d9f 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -17,7 +17,7 @@ use tracing::debug;
 
 use crate::consts::const_alloc_to_llvm;
 pub(crate) use crate::context::CodegenCx;
-use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, OperandBundleDef, True};
+use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, True};
 use crate::type_::Type;
 use crate::value::Value;
 
@@ -63,19 +63,19 @@ use crate::value::Value;
 /// the `OperandBundleDef` value created for MSVC landing pads.
 pub(crate) struct Funclet<'ll> {
     cleanuppad: &'ll Value,
-    operand: OperandBundleDef<'ll>,
+    operand: llvm::OperandBundleOwned<'ll>,
 }
 
 impl<'ll> Funclet<'ll> {
     pub(crate) fn new(cleanuppad: &'ll Value) -> Self {
-        Funclet { cleanuppad, operand: OperandBundleDef::new("funclet", &[cleanuppad]) }
+        Funclet { cleanuppad, operand: llvm::OperandBundleOwned::new("funclet", &[cleanuppad]) }
     }
 
     pub(crate) fn cleanuppad(&self) -> &'ll Value {
         self.cleanuppad
     }
 
-    pub(crate) fn bundle(&self) -> &OperandBundleDef<'ll> {
+    pub(crate) fn bundle(&self) -> &llvm::OperandBundle<'ll> {
         &self.operand
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index f33da42d63e..9778ff4918c 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -565,7 +565,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
             llvm::LLVMSetInitializer(g, array);
             llvm::set_linkage(g, llvm::Linkage::AppendingLinkage);
-            llvm::LLVMSetSection(g, c"llvm.metadata".as_ptr());
+            llvm::set_section(g, c"llvm.metadata");
         }
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 7947c9c8c8e..aef8642f199 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -72,7 +72,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
             let section_var = cx
                 .define_global(section_var_name, llvm_type)
                 .unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name));
-            llvm::LLVMSetSection(section_var, c".debug_gdb_scripts".as_ptr());
+            llvm::set_section(section_var, c".debug_gdb_scripts");
             llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents));
             llvm::LLVMSetGlobalConstant(section_var, llvm::True);
             llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 888d41d4726..8fc586d2c8f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -3,6 +3,7 @@
 
 use std::fmt::Debug;
 use std::marker::PhantomData;
+use std::ptr;
 
 use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
 use rustc_macros::TryFromU32;
@@ -708,8 +709,9 @@ unsafe extern "C" {
 }
 #[repr(C)]
 pub struct RustArchiveMember<'a>(InvariantOpaque<'a>);
+/// Opaque pointee of `LLVMOperandBundleRef`.
 #[repr(C)]
-pub struct OperandBundleDef<'a>(InvariantOpaque<'a>);
+pub(crate) struct OperandBundle<'a>(InvariantOpaque<'a>);
 #[repr(C)]
 pub struct Linker<'a>(InvariantOpaque<'a>);
 
@@ -1538,6 +1540,50 @@ unsafe extern "C" {
 
     pub fn LLVMGetOrInsertComdat(M: &Module, Name: *const c_char) -> &Comdat;
     pub fn LLVMSetComdat(V: &Value, C: &Comdat);
+
+    pub(crate) fn LLVMCreateOperandBundle(
+        Tag: *const c_char,
+        TagLen: size_t,
+        Args: *const &'_ Value,
+        NumArgs: c_uint,
+    ) -> *mut OperandBundle<'_>;
+    pub(crate) fn LLVMDisposeOperandBundle(Bundle: ptr::NonNull<OperandBundle<'_>>);
+
+    pub(crate) fn LLVMBuildCallWithOperandBundles<'a>(
+        B: &Builder<'a>,
+        Ty: &'a Type,
+        Fn: &'a Value,
+        Args: *const &'a Value,
+        NumArgs: c_uint,
+        Bundles: *const &OperandBundle<'a>,
+        NumBundles: c_uint,
+        Name: *const c_char,
+    ) -> &'a Value;
+    pub(crate) fn LLVMBuildInvokeWithOperandBundles<'a>(
+        B: &Builder<'a>,
+        Ty: &'a Type,
+        Fn: &'a Value,
+        Args: *const &'a Value,
+        NumArgs: c_uint,
+        Then: &'a BasicBlock,
+        Catch: &'a BasicBlock,
+        Bundles: *const &OperandBundle<'a>,
+        NumBundles: c_uint,
+        Name: *const c_char,
+    ) -> &'a Value;
+    pub(crate) fn LLVMBuildCallBr<'a>(
+        B: &Builder<'a>,
+        Ty: &'a Type,
+        Fn: &'a Value,
+        DefaultDest: &'a BasicBlock,
+        IndirectDests: *const &'a BasicBlock,
+        NumIndirectDests: c_uint,
+        Args: *const &'a Value,
+        NumArgs: c_uint,
+        Bundles: *const &OperandBundle<'a>,
+        NumBundles: c_uint,
+        Name: *const c_char,
+    ) -> &'a Value;
 }
 
 #[link(name = "llvm-wrapper", kind = "static")]
@@ -1623,47 +1669,11 @@ unsafe extern "C" {
         AttrsLen: size_t,
     );
 
-    pub fn LLVMRustBuildInvoke<'a>(
-        B: &Builder<'a>,
-        Ty: &'a Type,
-        Fn: &'a Value,
-        Args: *const &'a Value,
-        NumArgs: c_uint,
-        Then: &'a BasicBlock,
-        Catch: &'a BasicBlock,
-        OpBundles: *const &OperandBundleDef<'a>,
-        NumOpBundles: c_uint,
-        Name: *const c_char,
-    ) -> &'a Value;
-
-    pub fn LLVMRustBuildCallBr<'a>(
-        B: &Builder<'a>,
-        Ty: &'a Type,
-        Fn: &'a Value,
-        DefaultDest: &'a BasicBlock,
-        IndirectDests: *const &'a BasicBlock,
-        NumIndirectDests: c_uint,
-        Args: *const &'a Value,
-        NumArgs: c_uint,
-        OpBundles: *const &OperandBundleDef<'a>,
-        NumOpBundles: c_uint,
-        Name: *const c_char,
-    ) -> &'a Value;
-
     pub fn LLVMRustSetFastMath(Instr: &Value);
     pub fn LLVMRustSetAlgebraicMath(Instr: &Value);
     pub fn LLVMRustSetAllowReassoc(Instr: &Value);
 
     // Miscellaneous instructions
-    pub fn LLVMRustBuildCall<'a>(
-        B: &Builder<'a>,
-        Ty: &'a Type,
-        Fn: &'a Value,
-        Args: *const &'a Value,
-        NumArgs: c_uint,
-        OpBundles: *const &OperandBundleDef<'a>,
-        NumOpBundles: c_uint,
-    ) -> &'a Value;
     pub fn LLVMRustBuildMemCpy<'a>(
         B: &Builder<'a>,
         Dst: &'a Value,
@@ -2357,13 +2367,6 @@ unsafe extern "C" {
 
     pub fn LLVMRustSetDataLayoutFromTargetMachine<'a>(M: &'a Module, TM: &'a TargetMachine);
 
-    pub fn LLVMRustBuildOperandBundleDef(
-        Name: *const c_char,
-        Inputs: *const &'_ Value,
-        NumInputs: c_uint,
-    ) -> &mut OperandBundleDef<'_>;
-    pub fn LLVMRustFreeOperandBundleDef<'a>(Bundle: &'a mut OperandBundleDef<'a>);
-
     pub fn LLVMRustPositionBuilderAtStart<'a>(B: &Builder<'a>, BB: &'a BasicBlock);
 
     pub fn LLVMRustSetModulePICLevel(M: &Module);
@@ -2416,6 +2419,7 @@ unsafe extern "C" {
         data: *const u8,
         len: usize,
         name: *const u8,
+        name_len: usize,
         out_len: &mut usize,
     ) -> *const u8;
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index acd425bbb8e..00a5cd3b859 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -2,11 +2,12 @@
 
 use std::cell::RefCell;
 use std::ffi::{CStr, CString};
+use std::ops::Deref;
+use std::ptr;
 use std::str::FromStr;
 use std::string::FromUtf8Error;
 
 use libc::c_uint;
-use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_llvm::RustString;
 use rustc_target::abi::{Align, Size, WrappingRange};
 
@@ -331,28 +332,43 @@ pub fn last_error() -> Option<String> {
     }
 }
 
-pub struct OperandBundleDef<'a> {
-    pub raw: &'a mut ffi::OperandBundleDef<'a>,
+/// Owns an [`OperandBundle`], and will dispose of it when dropped.
+pub(crate) struct OperandBundleOwned<'a> {
+    raw: ptr::NonNull<OperandBundle<'a>>,
 }
 
-impl<'a> OperandBundleDef<'a> {
-    pub fn new(name: &str, vals: &[&'a Value]) -> Self {
-        let name = SmallCStr::new(name);
-        let def = unsafe {
-            LLVMRustBuildOperandBundleDef(name.as_ptr(), vals.as_ptr(), vals.len() as c_uint)
+impl<'a> OperandBundleOwned<'a> {
+    pub(crate) fn new(name: &str, vals: &[&'a Value]) -> Self {
+        let raw = unsafe {
+            LLVMCreateOperandBundle(
+                name.as_c_char_ptr(),
+                name.len(),
+                vals.as_ptr(),
+                vals.len() as c_uint,
+            )
         };
-        OperandBundleDef { raw: def }
+        OperandBundleOwned { raw: ptr::NonNull::new(raw).unwrap() }
     }
 }
 
-impl Drop for OperandBundleDef<'_> {
+impl Drop for OperandBundleOwned<'_> {
     fn drop(&mut self) {
         unsafe {
-            LLVMRustFreeOperandBundleDef(&mut *(self.raw as *mut _));
+            LLVMDisposeOperandBundle(self.raw);
         }
     }
 }
 
+impl<'a> Deref for OperandBundleOwned<'a> {
+    type Target = OperandBundle<'a>;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The returned reference is opaque and can only used for FFI.
+        // It is valid for as long as `&self` is.
+        unsafe { self.raw.as_ref() }
+    }
+}
+
 pub(crate) fn add_module_flag_u32(
     module: &Module,
     merge_behavior: ModuleFlagMergeBehavior,
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index b954633f453..cb4c9c078b1 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -21,7 +21,7 @@ use rustc_middle::mir::BinOp;
 use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypingMode};
 use rustc_session::Session;
 use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
 use rustc_span::symbol::sym;
@@ -119,7 +119,7 @@ pub fn validate_trivial_unsize<'tcx>(
 ) -> bool {
     match (source_data.principal(), target_data.principal()) {
         (Some(hr_source_principal), Some(hr_target_principal)) => {
-            let infcx = tcx.infer_ctxt().build();
+            let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
             let universe = infcx.universe();
             let ocx = ObligationCtxt::new(&infcx);
             infcx.enter_forall(hr_target_principal, |target_principal| {
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 004fb12419f..5210241d5e4 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -16,7 +16,7 @@ use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt, TypingMode};
 use rustc_mir_dataflow::Analysis;
 use rustc_mir_dataflow::impls::MaybeStorageLive;
 use rustc_mir_dataflow::storage::always_storage_live_locals;
@@ -64,8 +64,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
             let ConstCx { tcx, body, .. } = *ccx;
 
             FlowSensitiveAnalysis::new(NeedsDrop, ccx)
-                .into_engine(tcx, body)
-                .iterate_to_fixpoint()
+                .iterate_to_fixpoint(tcx, body, None)
                 .into_results_cursor(body)
         });
 
@@ -94,8 +93,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
             let ConstCx { tcx, body, .. } = *ccx;
 
             FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
-                .into_engine(tcx, body)
-                .iterate_to_fixpoint()
+                .iterate_to_fixpoint(tcx, body, None)
                 .into_results_cursor(body)
         });
 
@@ -124,8 +122,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
             let ConstCx { tcx, body, .. } = *ccx;
 
             FlowSensitiveAnalysis::new(HasMutInterior, ccx)
-                .into_engine(tcx, body)
-                .iterate_to_fixpoint()
+                .iterate_to_fixpoint(tcx, body, None)
                 .into_results_cursor(body)
         });
 
@@ -240,8 +237,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
                 let always_live_locals = &always_storage_live_locals(&ccx.body);
                 let mut maybe_storage_live =
                     MaybeStorageLive::new(Cow::Borrowed(always_live_locals))
-                        .into_engine(ccx.tcx, &ccx.body)
-                        .iterate_to_fixpoint()
+                        .iterate_to_fixpoint(ccx.tcx, &ccx.body, None)
                         .into_results_cursor(&ccx.body);
 
                 // And then check all `Return` in the MIR, and if a local is "maybe live" at a
@@ -593,7 +589,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 // Typeck only does a "non-const" check since it operates on HIR and cannot distinguish
                 // which path expressions are getting called on and which path expressions are only used
                 // as function pointers. This is required for correctness.
-                let infcx = tcx.infer_ctxt().build();
+                let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
                 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
                 let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args);
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 3ac06ae6491..3f977dc4b05 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -12,7 +12,7 @@ use rustc_middle::mir::CallSource;
 use rustc_middle::span_bug;
 use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
 use rustc_middle::ty::{
-    self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty,
+    self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty, TypingMode,
     suggest_constraining_type_param,
 };
 use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind};
@@ -116,7 +116,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                     let obligation =
                         Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
 
-                    let infcx = tcx.infer_ctxt().build();
+                    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
                     let mut selcx = SelectionContext::new(&infcx);
                     let implsrc = selcx.select(&obligation);
 
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index 547030a1854..e8637ba45cf 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -114,11 +114,11 @@ impl Qualif for HasMutInterior {
             ty::TraitRef::new(cx.tcx, freeze_def_id, [ty::GenericArg::from(ty)]),
         );
 
-        let infcx = cx
-            .tcx
-            .infer_ctxt()
-            .with_opaque_type_inference(cx.body.source.def_id().expect_local())
-            .build();
+        // FIXME(#132279): This should eventually use the already defined hidden types.
+        let infcx = cx.tcx.infer_ctxt().build(ty::TypingMode::analysis_in_body(
+            cx.tcx,
+            cx.body.source.def_id().expect_local(),
+        ));
         let ocx = ObligationCtxt::new(&infcx);
         ocx.register_obligation(obligation);
         let errors = ocx.select_all_or_error();
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index a1c773a4b80..d81368e9fcc 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -9,7 +9,9 @@ use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{
     self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
 };
-use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance};
+use rustc_middle::ty::{
+    self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypingMode, Variance,
+};
 use rustc_middle::{mir, span_bug};
 use rustc_session::Limit;
 use rustc_span::Span;
@@ -325,7 +327,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             return true;
         }
         // Slow path: spin up an inference context to check if these traits are sufficiently equal.
-        let infcx = self.tcx.infer_ctxt().build();
+        let infcx = self.tcx.infer_ctxt().build(TypingMode::from_param_env(self.param_env));
         let ocx = ObligationCtxt::new(&infcx);
         let cause = ObligationCause::dummy_with_span(self.cur_span());
         // equate the two trait refs after normalization
diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs
index 3ea54146fc7..7af977bab4d 100644
--- a/compiler/rustc_const_eval/src/util/compare_types.rs
+++ b/compiler/rustc_const_eval/src/util/compare_types.rs
@@ -5,7 +5,7 @@
 
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, Variance};
+use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, TypingMode, Variance};
 use rustc_trait_selection::traits::ObligationCtxt;
 
 /// Returns whether the two types are equal up to subtyping.
@@ -45,7 +45,8 @@ pub fn relate_types<'tcx>(
     }
 
     let mut builder = tcx.infer_ctxt().ignoring_regions();
-    let infcx = builder.build();
+    // FIXME(#132279): This should eventually use the already defined hidden types.
+    let infcx = builder.build(TypingMode::from_param_env(param_env));
     let ocx = ObligationCtxt::new(&infcx);
     let cause = ObligationCause::dummy();
     let src = ocx.normalize(&cause, param_env, src);
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index fcf3352bfc5..f26c7c1ba0b 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -74,7 +74,7 @@ expand_helper_attribute_name_invalid =
     `{$name}` cannot be a name of derive helper attribute
 
 expand_incomplete_parse =
-    macro expansion ignores token `{$token}` and any following
+    macro expansion ignores {$descr} and any tokens following
     .label = caused by the macro expansion here
     .note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context
     .suggestion_add_semi = you might be missing a semicolon here
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 5682c574552..7bd7c305539 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -275,7 +275,7 @@ pub(crate) struct UnsupportedKeyValue {
 pub(crate) struct IncompleteParse<'a> {
     #[primary_span]
     pub span: Span,
-    pub token: Cow<'a, str>,
+    pub descr: String,
     #[label]
     pub label_span: Span,
     pub macro_path: &'a ast::Path,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 5ffafcaa542..04ac7891023 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -21,6 +21,7 @@ use rustc_errors::PResult;
 use rustc_feature::Features;
 use rustc_parse::parser::{
     AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma,
+    token_descr,
 };
 use rustc_parse::validate_attr;
 use rustc_session::lint::BuiltinLintDiag;
@@ -1013,7 +1014,7 @@ pub(crate) fn ensure_complete_parse<'a>(
     span: Span,
 ) {
     if parser.token != token::Eof {
-        let token = pprust::token_to_string(&parser.token);
+        let descr = token_descr(&parser.token);
         // Avoid emitting backtrace info twice.
         let def_site_span = parser.token.span.with_ctxt(SyntaxContext::root());
 
@@ -1029,7 +1030,7 @@ pub(crate) fn ensure_complete_parse<'a>(
 
         parser.dcx().emit_err(IncompleteParse {
             span: def_site_span,
-            token,
+            descr,
             label_span: span,
             macro_path,
             kind_name,
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 103bbb05e7f..ffcce1e52f6 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -2,10 +2,9 @@ use std::borrow::Cow;
 
 use rustc_ast::token::{self, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
 use rustc_macros::Subdiagnostic;
-use rustc_parse::parser::{Parser, Recovery};
+use rustc_parse::parser::{Parser, Recovery, token_descr};
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::Ident;
@@ -336,17 +335,11 @@ pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Spa
 /// other tokens, this is "unexpected token...".
 pub(super) fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> {
     if let Some(expected_token) = expected_token {
-        Cow::from(format!(
-            "expected `{}`, found `{}`",
-            pprust::token_to_string(expected_token),
-            pprust::token_to_string(tok),
-        ))
+        Cow::from(format!("expected {}, found {}", token_descr(expected_token), token_descr(tok)))
     } else {
         match tok.kind {
             token::Eof => Cow::from("unexpected end of macro invocation"),
-            _ => {
-                Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok)))
-            }
+            _ => Cow::from(format!("no rules expected {}", token_descr(tok))),
         }
     }
 }
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index a08db612bbe..2a8dddc1e00 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -78,11 +78,10 @@ use std::rc::Rc;
 pub(crate) use NamedMatch::*;
 pub(crate) use ParseResult::*;
 use rustc_ast::token::{self, DocComment, NonterminalKind, Token};
-use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_lint_defs::pluralize;
-use rustc_parse::parser::{ParseNtResult, Parser};
+use rustc_parse::parser::{ParseNtResult, Parser, token_descr};
 use rustc_span::Span;
 use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent};
 
@@ -150,7 +149,7 @@ impl Display for MatcherLoc {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
             MatcherLoc::Token { token } | MatcherLoc::SequenceSep { separator: token } => {
-                write!(f, "`{}`", pprust::token_to_string(token))
+                write!(f, "{}", token_descr(token))
             }
             MatcherLoc::MetaVarDecl { bind, kind, .. } => {
                 write!(f, "meta-variable `${bind}")?;
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 6d04bdf7e48..f830108a02f 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -30,6 +30,7 @@ use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_type_ir::fold::TypeFoldable;
 use tracing::{debug, instrument};
+use ty::TypingMode;
 use {rustc_attr as attr, rustc_hir as hir};
 
 use super::compare_impl_item::{check_type_bounds, compare_impl_method, compare_impl_ty};
@@ -276,7 +277,8 @@ fn check_opaque_meets_bounds<'tcx>(
     };
     let param_env = tcx.param_env(defining_use_anchor);
 
-    let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build();
+    // FIXME(#132279): This should eventually use the already defined hidden types.
+    let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, defining_use_anchor));
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     let args = match *origin {
@@ -1675,8 +1677,8 @@ pub(super) fn check_coroutine_obligations(
         // typeck writeback gives us predicates with their regions erased.
         // As borrowck already has checked lifetimes, we do not need to do it again.
         .ignoring_regions()
-        .with_opaque_type_inference(def_id)
-        .build();
+        // FIXME(#132279): This should eventually use the already defined hidden types.
+        .build(TypingMode::analysis_in_body(tcx, def_id));
 
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
     for (predicate, cause) in &typeck_results.coroutine_stalled_predicates {
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 9de96b7ba77..db2c44fd29d 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::util::ExplicitSelf;
 use rustc_middle::ty::{
     self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeFolder,
-    TypeSuperFoldable, TypeVisitableExt, Upcast,
+    TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
@@ -228,7 +228,7 @@ fn compare_method_predicate_entailment<'tcx>(
     let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
     debug!(caller_bounds=?param_env.caller_bounds());
 
-    let infcx = &tcx.infer_ctxt().build();
+    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
     // Create obligations for each predicate declared by the impl
@@ -516,7 +516,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
         ObligationCause::misc(tcx.def_span(impl_m_def_id), impl_m_def_id),
     );
 
-    let infcx = &tcx.infer_ctxt().build();
+    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
     // Normalize the impl signature with fresh variables for lifetime inference.
@@ -1196,7 +1196,7 @@ fn compare_self_type<'tcx>(
         let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().input(0);
         let param_env = ty::ParamEnv::reveal_all();
 
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
         let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty);
         match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
@@ -1801,7 +1801,7 @@ fn compare_const_predicate_entailment<'tcx>(
         ObligationCause::misc(impl_ct_span, impl_ct_def_id),
     );
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     let impl_ct_own_bounds = impl_ct_predicates.instantiate_own_identity();
@@ -1951,7 +1951,7 @@ fn compare_type_predicate_entailment<'tcx>(
     let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
     debug!(caller_bounds=?param_env.caller_bounds());
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     for (predicate, span) in impl_ty_own_bounds {
@@ -2036,7 +2036,7 @@ pub(super) fn check_type_bounds<'tcx>(
     let impl_ty_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id);
     let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args);
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     // A synthetic impl Trait for RPITIT desugaring or assoc type for effects desugaring has no HIR,
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index 2d6b9813271..646c104f1f5 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -8,7 +8,7 @@ use rustc_middle::span_bug;
 use rustc_middle::traits::{ObligationCause, Reveal};
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt, TypeVisitor,
+    TypeVisitableExt, TypeVisitor, TypingMode,
 };
 use rustc_span::Span;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
@@ -132,7 +132,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
     let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing);
     let param_env = normalize_param_env_or_error(tcx, param_env, ObligationCause::dummy());
 
-    let ref infcx = tcx.infer_ctxt().build();
+    let ref infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new(infcx);
 
     // Normalize the bounds. This has two purposes:
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index 97a29b32c01..1c9bbe627fb 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -9,7 +9,7 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
 use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::util::CheckRegions;
-use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode};
 use rustc_trait_selection::regions::InferCtxtRegionExt;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 
@@ -124,7 +124,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     adt_def_id: LocalDefId,
     adt_to_impl_args: GenericArgsRef<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     let impl_span = tcx.def_span(drop_impl_def_id.to_def_id());
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index 7da2cd93d4e..0beb1f98d56 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -4,7 +4,7 @@ use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::span_bug;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
 use rustc_session::config::EntryFnType;
 use rustc_span::Span;
 use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
@@ -128,7 +128,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
             tcx.dcx().emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
             return;
         };
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let cause = traits::ObligationCause::new(
             return_ty_span,
             main_diagnostics_def_id,
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index ec5a89ec9d9..e9eea36a0e6 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -85,7 +85,7 @@ use rustc_infer::infer::{self, TyCtxtInferExt as _};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use rustc_session::parse::feature_err;
 use rustc_span::def_id::CRATE_DEF_ID;
@@ -530,7 +530,7 @@ fn suggestion_signature<'tcx>(
             let ty = tcx.type_of(assoc.def_id).instantiate_identity();
             let val = tcx
                 .infer_ctxt()
-                .build()
+                .build(TypingMode::non_body_analysis())
                 .err_ctxt()
                 .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
                 .unwrap_or_else(|| "value".to_string());
@@ -620,7 +620,7 @@ pub fn check_function_signature<'tcx>(
 
     let param_env = ty::ParamEnv::empty();
 
-    let infcx = &tcx.infer_ctxt().build();
+    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
     let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 499e42d31c9..12ed7b89f68 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
     self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable,
-    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast,
+    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::parse::feature_err;
@@ -106,7 +106,7 @@ where
     F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>) -> Result<(), ErrorGuaranteed>,
 {
     let param_env = tcx.param_env(body_def_id);
-    let infcx = &tcx.infer_ctxt().build();
+    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
     let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env };
@@ -765,7 +765,7 @@ fn test_region_obligations<'tcx>(
     // Unfortunately, we have to use a new `InferCtxt` each call, because
     // region constraints get added and solved there and we need to test each
     // call individually.
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
 
     add_constraints(&infcx);
 
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index b4f6b5a9dd2..5ff52376837 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -15,7 +15,9 @@ use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, suggest_constraining_type_params};
+use rustc_middle::ty::{
+    self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params,
+};
 use rustc_span::{DUMMY_SP, Span};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::misc::{
@@ -213,7 +215,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
 
     let param_env = tcx.param_env(impl_did);
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let cause = ObligationCause::misc(span, impl_did);
 
     // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw
@@ -354,7 +356,7 @@ pub(crate) fn coerce_unsized_info<'tcx>(
 
     debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let cause = ObligationCause::misc(span, impl_did);
     let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
                        mt_b: ty::TypeAndMut<'tcx>,
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 04770469132..8a1a887766c 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -7,7 +7,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION;
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor,
+    TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::{DefId, LocalDefId};
@@ -302,7 +302,7 @@ fn orphan_check<'tcx>(
     }
 
     // (1)  Instantiate all generic params with fresh inference vars.
-    let infcx = tcx.infer_ctxt().intercrate(true).build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::Coherence);
     let cause = traits::ObligationCause::dummy();
     let args = infcx.fresh_args_for_item(cause.span, impl_def_id.to_def_id());
     let trait_ref = trait_ref.instantiate(tcx, args);
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 3add801cf56..cca52c5142c 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -34,7 +34,7 @@ use rustc_infer::traits::ObligationCause;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::{Ident, Symbol, kw, sym};
 use rustc_span::{DUMMY_SP, Span};
@@ -1438,9 +1438,11 @@ fn infer_return_ty_for_fn_sig<'tcx>(
                     Applicability::MachineApplicable,
                 );
                 recovered_ret_ty = Some(suggestable_ret_ty);
-            } else if let Some(sugg) =
-                suggest_impl_trait(&tcx.infer_ctxt().build(), tcx.param_env(def_id), ret_ty)
-            {
+            } else if let Some(sugg) = suggest_impl_trait(
+                &tcx.infer_ctxt().build(TypingMode::non_body_analysis()),
+                tcx.param_env(def_id),
+                ret_ty,
+            ) {
                 diag.span_suggestion(
                     ty.span,
                     "replace with an appropriate return type",
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 0891642f2c8..2d0c3ec28c3 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -39,7 +39,7 @@ use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
 use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
 use rustc_middle::ty::{
     self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
-    TypeVisitableExt,
+    TypeVisitableExt, TypingMode,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@@ -1300,7 +1300,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             Some(infcx) => infcx,
             None => {
                 assert!(!self_ty.has_infer());
-                infcx_ = tcx.infer_ctxt().ignoring_regions().build();
+                infcx_ = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
                 &infcx_
             }
         };
@@ -1492,7 +1492,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             infcx
         } else {
             assert!(!qself_ty.has_infer());
-            infcx_ = tcx.infer_ctxt().build();
+            infcx_ = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
             &infcx_
         };
 
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 2fa4ca68073..5b0165bf993 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -5,7 +5,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{ObligationCause, WellFormedLoc};
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_span::def_id::LocalDefId;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 use tracing::debug;
@@ -68,7 +68,7 @@ fn diagnostic_hir_wf_check<'tcx>(
 
     impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
         fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-            let infcx = self.tcx.infer_ctxt().build();
+            let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
             let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
             let tcx_ty = self.icx.lower_ty(ty);
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index a394fc2fbb1..b0c9aed5d85 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -72,7 +72,9 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::traits::specialization_graph::Node;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
-use rustc_middle::ty::{self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt, TypingMode,
+};
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
@@ -195,7 +197,7 @@ fn get_impl_args(
     impl1_def_id: LocalDefId,
     impl2_node: Node,
 ) -> Result<(GenericArgsRef<'_>, GenericArgsRef<'_>), ErrorGuaranteed> {
-    let infcx = &tcx.infer_ctxt().build();
+    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(infcx);
     let param_env = tcx.param_env(impl1_def_id);
     let impl1_span = tcx.def_span(impl1_def_id);
@@ -409,7 +411,7 @@ fn check_predicates<'tcx>(
 
     // Include the well-formed predicates of the type parameters of the impl.
     for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().instantiate_identity().args {
-        let infcx = &tcx.infer_ctxt().build();
+        let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let obligations =
             wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, arg, span)
                 .unwrap();
diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
index 18e40cfa428..903be7e732a 100644
--- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
+++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
@@ -8,7 +8,7 @@ use rustc_hir::{HirId, HirIdMap};
 use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use rustc_middle::span_bug;
 use rustc_middle::ty::visit::TypeVisitableExt;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefIdMap;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -81,7 +81,8 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
     pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
         let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner;
 
-        let infcx = tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(def_id).build();
+        let infcx =
+            tcx.infer_ctxt().ignoring_regions().build(TypingMode::analysis_in_body(tcx, def_id));
         let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
 
         TypeckRootCtxt {
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 8c943a961e7..3eda3e9c67e 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -28,7 +28,7 @@
 use relate::lattice::{LatticeOp, LatticeOpKind};
 use rustc_middle::bug;
 use rustc_middle::ty::relate::solver_relating::RelateExt as NextSolverRelate;
-use rustc_middle::ty::{Const, ImplSubject};
+use rustc_middle::ty::{Const, ImplSubject, TypingMode};
 
 use super::*;
 use crate::infer::relate::type_relating::TypeRelating;
@@ -67,30 +67,48 @@ impl<'tcx> InferCtxt<'tcx> {
     /// variables in the same state. This can be used to "branch off" many tests from the same
     /// common state.
     pub fn fork(&self) -> Self {
-        self.fork_with_intercrate(self.intercrate)
+        Self {
+            tcx: self.tcx,
+            typing_mode: self.typing_mode,
+            considering_regions: self.considering_regions,
+            skip_leak_check: self.skip_leak_check,
+            inner: self.inner.clone(),
+            lexical_region_resolutions: self.lexical_region_resolutions.clone(),
+            selection_cache: self.selection_cache.clone(),
+            evaluation_cache: self.evaluation_cache.clone(),
+            reported_trait_errors: self.reported_trait_errors.clone(),
+            reported_signature_mismatch: self.reported_signature_mismatch.clone(),
+            tainted_by_errors: self.tainted_by_errors.clone(),
+            universe: self.universe.clone(),
+            next_trait_solver: self.next_trait_solver,
+            obligation_inspector: self.obligation_inspector.clone(),
+        }
     }
 
     /// Forks the inference context, creating a new inference context with the same inference
     /// variables in the same state, except possibly changing the intercrate mode. This can be
     /// used to "branch off" many tests from the same common state. Used in negative coherence.
-    pub fn fork_with_intercrate(&self, intercrate: bool) -> Self {
-        Self {
+    pub fn fork_with_typing_mode(&self, typing_mode: TypingMode<'tcx>) -> Self {
+        // Unlike `fork`, this invalidates all cache entries as they may depend on the
+        // typing mode.
+        let forked = Self {
             tcx: self.tcx,
-            defining_opaque_types: self.defining_opaque_types,
+            typing_mode,
             considering_regions: self.considering_regions,
             skip_leak_check: self.skip_leak_check,
             inner: self.inner.clone(),
             lexical_region_resolutions: self.lexical_region_resolutions.clone(),
-            selection_cache: self.selection_cache.clone(),
-            evaluation_cache: self.evaluation_cache.clone(),
+            selection_cache: Default::default(),
+            evaluation_cache: Default::default(),
             reported_trait_errors: self.reported_trait_errors.clone(),
             reported_signature_mismatch: self.reported_signature_mismatch.clone(),
             tainted_by_errors: self.tainted_by_errors.clone(),
             universe: self.universe.clone(),
-            intercrate,
             next_trait_solver: self.next_trait_solver,
             obligation_inspector: self.obligation_inspector.clone(),
-        }
+        };
+        forked.inner.borrow_mut().projection_cache().clear();
+        forked
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 90d07964fda..c9d8ebecef0 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -46,7 +46,7 @@ impl<'tcx> InferCtxt<'tcx> {
         V: TypeFoldable<TyCtxt<'tcx>>,
     {
         let (param_env, value) = value.into_parts();
-        let param_env = self.tcx.canonical_param_env_cache.get_or_insert(
+        let canonical_param_env = self.tcx.canonical_param_env_cache.get_or_insert(
             self.tcx,
             param_env,
             query_state,
@@ -64,7 +64,7 @@ impl<'tcx> InferCtxt<'tcx> {
         );
 
         let canonical = Canonicalizer::canonicalize_with_base(
-            param_env,
+            canonical_param_env,
             value,
             Some(self),
             self.tcx,
@@ -72,7 +72,7 @@ impl<'tcx> InferCtxt<'tcx> {
             query_state,
         )
         .unchecked_map(|(param_env, value)| param_env.and(value));
-        CanonicalQueryInput { canonical, defining_opaque_types: self.defining_opaque_types() }
+        CanonicalQueryInput { canonical, typing_mode: self.typing_mode(param_env) }
     }
 
     /// Canonicalizes a query *response* `V`. When we canonicalize a
diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs
index 0c151a11ad4..ecda9c6eb00 100644
--- a/compiler/rustc_infer/src/infer/context.rs
+++ b/compiler/rustc_infer/src/infer/context.rs
@@ -1,7 +1,6 @@
 ///! Definition of `InferCtxtLike` from the librarified type layer.
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::traits::solve::SolverMode;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::relate::RelateResult;
 use rustc_middle::ty::relate::combine::PredicateEmittingRelation;
@@ -21,11 +20,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
         self.next_trait_solver
     }
 
-    fn solver_mode(&self) -> ty::solve::SolverMode {
-        match self.intercrate {
-            true => SolverMode::Coherence,
-            false => SolverMode::Normal,
-        }
+    fn typing_mode(
+        &self,
+        param_env_for_debug_assertion: ty::ParamEnv<'tcx>,
+    ) -> ty::TypingMode<'tcx> {
+        self.typing_mode(param_env_for_debug_assertion)
     }
 
     fn universe(&self) -> ty::UniverseIndex {
@@ -91,10 +90,6 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
         self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
     }
 
-    fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
-        self.defining_opaque_types()
-    }
-
     fn next_ty_infer(&self) -> Ty<'tcx> {
         self.next_ty_var(DUMMY_SP)
     }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index be43cba97f0..fc54d69449f 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -38,11 +38,12 @@ use rustc_middle::ty::fold::{
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{
     self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
-    GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid,
+    GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 use rustc_span::symbol::Symbol;
+use rustc_type_ir::solve::Reveal;
 use snapshot::undo_log::InferCtxtUndoLogs;
 use tracing::{debug, instrument};
 use type_variable::TypeVariableOrigin;
@@ -243,8 +244,9 @@ impl<'tcx> InferCtxtInner<'tcx> {
 pub struct InferCtxt<'tcx> {
     pub tcx: TyCtxt<'tcx>,
 
-    /// The `DefIds` of the opaque types that may have their hidden types constrained.
-    defining_opaque_types: &'tcx ty::List<LocalDefId>,
+    /// The mode of this inference context, see the struct documentation
+    /// for more details.
+    typing_mode: TypingMode<'tcx>,
 
     /// Whether this inference context should care about region obligations in
     /// the root universe. Most notably, this is used during hir typeck as region
@@ -296,26 +298,6 @@ pub struct InferCtxt<'tcx> {
     /// bound.
     universe: Cell<ty::UniverseIndex>,
 
-    /// During coherence we have to assume that other crates may add
-    /// additional impls which we currently don't know about.
-    ///
-    /// To deal with this evaluation, we should be conservative
-    /// and consider the possibility of impls from outside this crate.
-    /// This comes up primarily when resolving ambiguity. Imagine
-    /// there is some trait reference `$0: Bar` where `$0` is an
-    /// inference variable. If `intercrate` is true, then we can never
-    /// say for sure that this reference is not implemented, even if
-    /// there are *no impls at all for `Bar`*, because `$0` could be
-    /// bound to some type that in a downstream crate that implements
-    /// `Bar`.
-    ///
-    /// Outside of coherence, we set this to false because we are only
-    /// interested in types that the user could actually have written.
-    /// In other words, we consider `$0: Bar` to be unimplemented if
-    /// there is no type that the user could *actually name* that
-    /// would satisfy it. This avoids crippling inference, basically.
-    pub intercrate: bool,
-
     next_trait_solver: bool,
 
     pub obligation_inspector: Cell<Option<ObligationInspector<'tcx>>>,
@@ -529,11 +511,8 @@ pub struct RegionObligation<'tcx> {
 /// Used to configure inference contexts before their creation.
 pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
-    defining_opaque_types: &'tcx ty::List<LocalDefId>,
     considering_regions: bool,
     skip_leak_check: bool,
-    /// Whether we are in coherence mode.
-    intercrate: bool,
     /// Whether we should use the new trait solver in the local inference context,
     /// which affects things like which solver is used in `predicate_may_hold`.
     next_trait_solver: bool,
@@ -544,37 +523,19 @@ impl<'tcx> TyCtxt<'tcx> {
     fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
         InferCtxtBuilder {
             tcx: self,
-            defining_opaque_types: ty::List::empty(),
             considering_regions: true,
             skip_leak_check: false,
-            intercrate: false,
             next_trait_solver: self.next_trait_solver_globally(),
         }
     }
 }
 
 impl<'tcx> InferCtxtBuilder<'tcx> {
-    /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
-    /// you need to call this function. Otherwise the opaque type will be treated opaquely.
-    ///
-    /// It is only meant to be called in two places, for typeck
-    /// (via `Inherited::build`) and for the inference context used
-    /// in mir borrowck.
-    pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self {
-        self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor);
-        self
-    }
-
     pub fn with_next_trait_solver(mut self, next_trait_solver: bool) -> Self {
         self.next_trait_solver = next_trait_solver;
         self
     }
 
-    pub fn intercrate(mut self, intercrate: bool) -> Self {
-        self.intercrate = intercrate;
-        self
-    }
-
     pub fn ignoring_regions(mut self) -> Self {
         self.considering_regions = false;
         self
@@ -600,24 +561,17 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
-        self.defining_opaque_types = input.defining_opaque_types;
-        let infcx = self.build();
+        let infcx = self.build(input.typing_mode);
         let (value, args) = infcx.instantiate_canonical(span, &input.canonical);
         (infcx, value, args)
     }
 
-    pub fn build(&mut self) -> InferCtxt<'tcx> {
-        let InferCtxtBuilder {
-            tcx,
-            defining_opaque_types,
-            considering_regions,
-            skip_leak_check,
-            intercrate,
-            next_trait_solver,
-        } = *self;
+    pub fn build(&mut self, typing_mode: TypingMode<'tcx>) -> InferCtxt<'tcx> {
+        let InferCtxtBuilder { tcx, considering_regions, skip_leak_check, next_trait_solver } =
+            *self;
         InferCtxt {
             tcx,
-            defining_opaque_types,
+            typing_mode,
             considering_regions,
             skip_leak_check,
             inner: RefCell::new(InferCtxtInner::new()),
@@ -628,7 +582,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
             reported_signature_mismatch: Default::default(),
             tainted_by_errors: Cell::new(None),
             universe: Cell::new(ty::UniverseIndex::ROOT),
-            intercrate,
             next_trait_solver,
             obligation_inspector: Cell::new(None),
         }
@@ -659,14 +612,30 @@ impl<'tcx> InferCtxt<'tcx> {
         self.tcx.dcx().taintable_handle(&self.tainted_by_errors)
     }
 
-    pub fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
-        self.defining_opaque_types
-    }
-
     pub fn next_trait_solver(&self) -> bool {
         self.next_trait_solver
     }
 
+    #[inline(always)]
+    pub fn typing_mode(
+        &self,
+        param_env_for_debug_assertion: ty::ParamEnv<'tcx>,
+    ) -> TypingMode<'tcx> {
+        if cfg!(debug_assertions) {
+            match (param_env_for_debug_assertion.reveal(), self.typing_mode) {
+                (Reveal::All, TypingMode::PostAnalysis)
+                | (Reveal::UserFacing, TypingMode::Coherence | TypingMode::Analysis { .. }) => {}
+                (r, t) => unreachable!("TypingMode x Reveal mismatch: {r:?} {t:?}"),
+            }
+        }
+        self.typing_mode
+    }
+
+    #[inline(always)]
+    pub fn typing_mode_unchecked(&self) -> TypingMode<'tcx> {
+        self.typing_mode
+    }
+
     pub fn freshen<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
         t.fold_with(&mut self.freshener())
     }
@@ -1029,8 +998,12 @@ impl<'tcx> InferCtxt<'tcx> {
 
     #[inline(always)]
     pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
-        let Some(id) = id.into().as_local() else { return false };
-        self.defining_opaque_types.contains(&id)
+        match self.typing_mode_unchecked() {
+            TypingMode::Analysis { defining_opaque_types } => {
+                id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id))
+            }
+            TypingMode::Coherence | TypingMode::PostAnalysis => false,
+        }
     }
 
     pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index c38b7114e43..498d25aea64 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -2,6 +2,7 @@ use hir::def_id::{DefId, LocalDefId};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
+use rustc_middle::bug;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::solve::Goal;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -100,7 +101,7 @@ impl<'tcx> InferCtxt<'tcx> {
         let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
                 let def_id = def_id.expect_local();
-                if self.intercrate {
+                if let ty::TypingMode::Coherence = self.typing_mode(param_env) {
                     // See comment on `insert_hidden_type` for why this is sufficient in coherence
                     return Some(self.register_hidden_type(
                         OpaqueTypeKey { def_id, args },
@@ -519,28 +520,32 @@ impl<'tcx> InferCtxt<'tcx> {
         // value being folded. In simple cases like `-> impl Foo`,
         // these are the same span, but not in cases like `-> (impl
         // Foo, impl Bar)`.
-        if self.intercrate {
-            // During intercrate we do not define opaque types but instead always
-            // force ambiguity unless the hidden type is known to not implement
-            // our trait.
-            goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous))
-        } else {
-            let prev = self
-                .inner
-                .borrow_mut()
-                .opaque_types()
-                .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
-            if let Some(prev) = prev {
-                goals.extend(
-                    self.at(&ObligationCause::dummy_with_span(span), param_env)
-                        .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)?
-                        .obligations
-                        .into_iter()
-                        // FIXME: Shuttling between obligations and goals is awkward.
-                        .map(Goal::from),
-                );
+        match self.typing_mode(param_env) {
+            ty::TypingMode::Coherence => {
+                // During intercrate we do not define opaque types but instead always
+                // force ambiguity unless the hidden type is known to not implement
+                // our trait.
+                goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous));
             }
-        };
+            ty::TypingMode::Analysis { .. } => {
+                let prev = self
+                    .inner
+                    .borrow_mut()
+                    .opaque_types()
+                    .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
+                if let Some(prev) = prev {
+                    goals.extend(
+                        self.at(&ObligationCause::dummy_with_span(span), param_env)
+                            .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)?
+                            .obligations
+                            .into_iter()
+                            // FIXME: Shuttling between obligations and goals is awkward.
+                            .map(Goal::from),
+                    );
+                }
+            }
+            ty::TypingMode::PostAnalysis => bug!("insert hidden type post-analysis"),
+        }
 
         Ok(())
     }
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 32817dbcb21..4c80bf4e07e 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -9,6 +9,7 @@ use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::visit::MaxUniverse;
 use rustc_middle::ty::{
     self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeVisitable, TypeVisitableExt,
+    TypingMode,
 };
 use rustc_span::Span;
 use tracing::{debug, instrument, warn};
@@ -519,7 +520,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
                             //
                             // cc trait-system-refactor-initiative#108
                             if self.infcx.next_trait_solver()
-                                && !self.infcx.intercrate
+                                && !matches!(
+                                    self.infcx.typing_mode_unchecked(),
+                                    TypingMode::Coherence
+                                )
                                 && self.in_alias
                             {
                                 inner.type_variables().equate(vid, new_var_id);
@@ -650,7 +654,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
                             // See the comment for type inference variables
                             // for more details.
                             if self.infcx.next_trait_solver()
-                                && !self.infcx.intercrate
+                                && !matches!(
+                                    self.infcx.typing_mode_unchecked(),
+                                    TypingMode::Coherence
+                                )
                                 && self.in_alias
                             {
                                 variable_table.union(vid, new_var_id);
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index dbb8c667532..77682ea9341 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -31,7 +31,7 @@ use rustc_middle::bug;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, VariantDef};
 use rustc_session::lint::FutureIncompatibilityReason;
 // hardwired lints from rustc_lint_defs
 pub use rustc_session::lint::builtin::*;
@@ -604,7 +604,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
             && cx
                 .tcx
                 .infer_ctxt()
-                .build()
+                .build(cx.typing_mode())
                 .type_implements_trait(iter_trait, [ty], cx.param_env)
                 .must_apply_modulo_regions()
         {
@@ -648,7 +648,9 @@ fn type_implements_negative_copy_modulo_regions<'tcx>(
         predicate: pred.upcast(tcx),
     };
 
-    tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
+    tcx.infer_ctxt()
+        .build(TypingMode::non_body_analysis())
+        .predicate_must_hold_modulo_regions(&obligation)
 }
 
 declare_lint! {
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 699088914e8..aa7ec2659d0 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -14,11 +14,12 @@ use rustc_feature::Features;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc_infer::traits::Reveal;
 use rustc_middle::bug;
 use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
-use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingMode};
 use rustc_session::lint::{
     BuiltinLintDiag, FutureIncompatibleInfo, Level, Lint, LintBuffer, LintExpectationId, LintId,
 };
@@ -698,6 +699,15 @@ impl LintContext for EarlyContext<'_> {
 }
 
 impl<'tcx> LateContext<'tcx> {
+    /// The typing mode of the currently visited node. Use this when
+    /// building a new `InferCtxt`.
+    pub fn typing_mode(&self) -> TypingMode<'tcx> {
+        debug_assert_eq!(self.param_env.reveal(), Reveal::UserFacing);
+        // FIXME(#132279): In case we're in a body, we should use a typing
+        // mode which reveals the opaque types defined by that body.
+        TypingMode::non_body_analysis()
+    }
+
     /// Gets the type-checking results for the current body,
     /// or `None` if outside a body.
     pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index fcb7a6108c0..cf68e41243f 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -166,7 +166,7 @@ fn suggest_question_mark<'tcx>(
     }
 
     let ty = args.type_at(0);
-    let infcx = cx.tcx.infer_ctxt().build();
+    let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
     let ocx = ObligationCtxt::new(&infcx);
 
     let body_def_id = cx.tcx.hir().body_owner_def_id(body_id);
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index cc40b67ab27..026826021c8 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::relate::{
     Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys,
 };
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
+    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::FutureIncompatibilityReason;
@@ -184,7 +184,7 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) {
         }),
         outlives_env: LazyCell::new(|| {
             let param_env = tcx.param_env(parent_def_id);
-            let infcx = tcx.infer_ctxt().build();
+            let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
             let ocx = ObligationCtxt::new(&infcx);
             let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default();
             let implied_bounds =
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 51877e8a034..cf25ec99e67 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -157,7 +157,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
                 Some(ty_def) if cx.tcx.is_lang_item(ty_def.did(), LangItem::String),
             );
 
-            let infcx = cx.tcx.infer_ctxt().build();
+            let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
             let suggest_display = is_str
                 || cx.tcx.get_diagnostic_item(sym::Display).is_some_and(|t| {
                     infcx.type_implements_trait(t, [ty], cx.param_env).may_apply()
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index ffbcf7f808e..16a1a5a72bc 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
         }
 
         let def_id = opaque.def_id.to_def_id();
-        let infcx = &cx.tcx.infer_ctxt().build();
+        let infcx = &cx.tcx.infer_ctxt().build(cx.typing_mode());
         // For every projection predicate in the opaque type's explicit bounds,
         // check that the type that we're assigning actually satisfies the bounds
         // of the associated type.
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 20bf32d731e..3e906f89c15 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -1559,8 +1559,10 @@ extern "C" LLVMModuleRef LLVMRustParseBitcodeForLTO(LLVMContextRef Context,
 extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data,
                                                             size_t len,
                                                             const char *name,
+                                                            size_t name_len,
                                                             size_t *out_len) {
   *out_len = 0;
+  auto Name = StringRef(name, name_len);
   auto Data = StringRef(data, len);
   auto Buffer = MemoryBufferRef(Data, ""); // The id is unused.
   file_magic Type = identify_magic(Buffer.getBuffer());
@@ -1571,8 +1573,8 @@ extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data,
     return nullptr;
   }
   for (const object::SectionRef &Sec : (*ObjFileOrError)->sections()) {
-    Expected<StringRef> Name = Sec.getName();
-    if (Name && *Name == name) {
+    Expected<StringRef> SecName = Sec.getName();
+    if (SecName && *SecName == Name) {
       Expected<StringRef> SectionOrError = Sec.getContents();
       if (!SectionOrError) {
         LLVMRustSetLastError(toString(SectionOrError.takeError()).c_str());
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index b3dab6d512e..645b4082be5 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1537,38 +1537,6 @@ LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, RustStringRef MessageOut,
   return true;
 }
 
-extern "C" OperandBundleDef *LLVMRustBuildOperandBundleDef(const char *Name,
-                                                           LLVMValueRef *Inputs,
-                                                           unsigned NumInputs) {
-  return new OperandBundleDef(Name,
-                              ArrayRef<Value *>(unwrap(Inputs), NumInputs));
-}
-
-extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) {
-  delete Bundle;
-}
-
-// OpBundlesIndirect is an array of pointers (*not* a pointer to an array).
-extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty,
-                                          LLVMValueRef Fn, LLVMValueRef *Args,
-                                          unsigned NumArgs,
-                                          OperandBundleDef **OpBundlesIndirect,
-                                          unsigned NumOpBundles) {
-  Value *Callee = unwrap(Fn);
-  FunctionType *FTy = unwrap<FunctionType>(Ty);
-
-  // FIXME: Is there a way around this?
-  SmallVector<OperandBundleDef> OpBundles;
-  OpBundles.reserve(NumOpBundles);
-  for (unsigned i = 0; i < NumOpBundles; ++i) {
-    OpBundles.push_back(*OpBundlesIndirect[i]);
-  }
-
-  return wrap(unwrap(B)->CreateCall(FTy, Callee,
-                                    ArrayRef<Value *>(unwrap(Args), NumArgs),
-                                    ArrayRef<OperandBundleDef>(OpBundles)));
-}
-
 extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst,
                                             unsigned DstAlign, LLVMValueRef Src,
                                             unsigned SrcAlign,
@@ -1596,37 +1564,18 @@ extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B, LLVMValueRef Dst,
                                       MaybeAlign(DstAlign), IsVolatile));
 }
 
-// OpBundlesIndirect is an array of pointers (*not* a pointer to an array).
-extern "C" LLVMValueRef
-LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
-                    LLVMValueRef *Args, unsigned NumArgs,
-                    LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
-                    OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles,
-                    const char *Name) {
-  Value *Callee = unwrap(Fn);
-  FunctionType *FTy = unwrap<FunctionType>(Ty);
-
-  // FIXME: Is there a way around this?
-  SmallVector<OperandBundleDef> OpBundles;
-  OpBundles.reserve(NumOpBundles);
-  for (unsigned i = 0; i < NumOpBundles; ++i) {
-    OpBundles.push_back(*OpBundlesIndirect[i]);
-  }
-
-  return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch),
-                                      ArrayRef<Value *>(unwrap(Args), NumArgs),
-                                      ArrayRef<OperandBundleDef>(OpBundles),
-                                      Name));
-}
+// Polyfill for `LLVMBuildCallBr`, which was added in LLVM 19.
+// <https://github.com/llvm/llvm-project/commit/584253c4e2f788f870488fc32193b52d67ddaccc>
+// FIXME: Remove when Rust's minimum supported LLVM version reaches 19.
+#if LLVM_VERSION_LT(19, 0)
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OperandBundleDef, LLVMOperandBundleRef)
 
-// OpBundlesIndirect is an array of pointers (*not* a pointer to an array).
 extern "C" LLVMValueRef
-LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
-                    LLVMBasicBlockRef DefaultDest,
-                    LLVMBasicBlockRef *IndirectDests, unsigned NumIndirectDests,
-                    LLVMValueRef *Args, unsigned NumArgs,
-                    OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles,
-                    const char *Name) {
+LLVMBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
+                LLVMBasicBlockRef DefaultDest, LLVMBasicBlockRef *IndirectDests,
+                unsigned NumIndirectDests, LLVMValueRef *Args, unsigned NumArgs,
+                LLVMOperandBundleRef *Bundles, unsigned NumBundles,
+                const char *Name) {
   Value *Callee = unwrap(Fn);
   FunctionType *FTy = unwrap<FunctionType>(Ty);
 
@@ -1639,9 +1588,9 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
 
   // FIXME: Is there a way around this?
   SmallVector<OperandBundleDef> OpBundles;
-  OpBundles.reserve(NumOpBundles);
-  for (unsigned i = 0; i < NumOpBundles; ++i) {
-    OpBundles.push_back(*OpBundlesIndirect[i]);
+  OpBundles.reserve(NumBundles);
+  for (unsigned i = 0; i < NumBundles; ++i) {
+    OpBundles.push_back(*unwrap(Bundles[i]));
   }
 
   return wrap(
@@ -1650,6 +1599,7 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
                               ArrayRef<Value *>(unwrap(Args), NumArgs),
                               ArrayRef<OperandBundleDef>(OpBundles), Name));
 }
+#endif
 
 extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B,
                                                LLVMBasicBlockRef BB) {
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 564d274bc8b..57da5b39ba7 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -323,7 +323,7 @@ macro_rules! define_callbacks {
                 // Increase this limit if necessary, but do try to keep the size low if possible
                 #[cfg(target_pointer_width = "64")]
                 const _: () = {
-                    if mem::size_of::<Key<'static>>() > 72 {
+                    if mem::size_of::<Key<'static>>() > 80 {
                         panic!("{}", concat!(
                             "the query `",
                             stringify!($name),
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 5ae9c589ec4..5cbbc80ebfb 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -54,7 +54,6 @@ use rustc_type_ir::TyKind::*;
 use rustc_type_ir::fold::TypeFoldable;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 pub use rustc_type_ir::lift::Lift;
-use rustc_type_ir::solve::SolverMode;
 use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph};
 use tracing::{debug, trace};
 
@@ -170,15 +169,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         tracked.get(self)
     }
 
-    fn with_global_cache<R>(
-        self,
-        mode: SolverMode,
-        f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
-    ) -> R {
-        match mode {
-            SolverMode::Normal => f(&mut *self.new_solver_evaluation_cache.lock()),
-            SolverMode::Coherence => f(&mut *self.new_solver_coherence_evaluation_cache.lock()),
-        }
+    fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R {
+        f(&mut *self.new_solver_evaluation_cache.lock())
     }
 
     fn evaluation_is_concurrent(&self) -> bool {
@@ -629,6 +621,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     ) -> ty::Binder<'tcx, T> {
         self.anonymize_bound_vars(binder)
     }
+
+    fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::DefiningOpaqueTypes {
+        self.opaque_types_defined_by(defining_anchor)
+    }
 }
 
 macro_rules! bidirectional_lang_item_map {
@@ -1334,7 +1330,6 @@ pub struct GlobalCtxt<'tcx> {
 
     /// Caches the results of goal evaluation in the new solver.
     pub new_solver_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>,
-    pub new_solver_coherence_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>,
 
     pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>,
 
@@ -1561,7 +1556,6 @@ impl<'tcx> TyCtxt<'tcx> {
             selection_cache: Default::default(),
             evaluation_cache: Default::default(),
             new_solver_evaluation_cache: Default::default(),
-            new_solver_coherence_evaluation_cache: Default::default(),
             canonical_param_env_cache: Default::default(),
             data_layout,
             alloc_map: Lock::new(interpret::AllocMap::new()),
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index b92fc864b49..bd32e5837b3 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -100,7 +100,7 @@ pub use self::rvalue_scopes::RvalueScopes;
 pub use self::sty::{
     AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
     CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst,
-    ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs,
+    ParamTy, PolyFnSig, TyKind, TypeAndMut, TypingMode, UpvarArgs,
 };
 pub use self::trait_def::TraitDef;
 pub use self::typeck_results::{
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index d8362ccc0a9..a8327ebc17f 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -40,6 +40,7 @@ pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>;
 pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>;
 pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>;
 pub type EarlyBinder<'tcx, T> = ir::EarlyBinder<TyCtxt<'tcx>, T>;
+pub type TypingMode<'tcx> = ir::TypingMode<TyCtxt<'tcx>>;
 
 pub trait Article {
     fn article(&self) -> &'static str;
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 8c20d2e0d3a..e15ea4d8d8b 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -16,7 +16,7 @@ use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir};
-use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
@@ -500,7 +500,9 @@ fn construct_fn<'tcx>(
         );
     }
 
-    let infcx = tcx.infer_ctxt().build();
+    // FIXME(#132279): This should be able to reveal opaque
+    // types defined during HIR typeck.
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let mut builder = Builder::new(
         thir,
         infcx,
@@ -578,7 +580,9 @@ fn construct_const<'a, 'tcx>(
         _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def),
     };
 
-    let infcx = tcx.infer_ctxt().build();
+    // FIXME(#132279): We likely want to be able to use the hidden types of
+    // opaques used by this function here.
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let mut builder =
         Builder::new(thir, infcx, def, hir_id, span, 0, const_ty, const_ty_span, None);
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 8498df59ce6..f222a869c03 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -79,6 +79,8 @@ enum LetSource {
     IfLetGuard,
     LetElse,
     WhileLet,
+    Else,
+    ElseIfLet,
 }
 
 struct MatchVisitor<'p, 'tcx> {
@@ -129,15 +131,20 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {
                 // Give a specific `let_source` for the condition.
                 let let_source = match ex.span.desugaring_kind() {
                     Some(DesugaringKind::WhileLoop) => LetSource::WhileLet,
-                    _ => LetSource::IfLet,
+                    _ => match self.let_source {
+                        LetSource::Else => LetSource::ElseIfLet,
+                        _ => LetSource::IfLet,
+                    },
                 };
                 self.with_let_source(let_source, |this| this.visit_expr(&self.thir[cond]));
                 self.with_let_source(LetSource::None, |this| {
                     this.visit_expr(&this.thir[then]);
-                    if let Some(else_) = else_opt {
-                        this.visit_expr(&this.thir[else_]);
-                    }
                 });
+                if let Some(else_) = else_opt {
+                    self.with_let_source(LetSource::Else, |this| {
+                        this.visit_expr(&this.thir[else_])
+                    });
+                }
                 return;
             }
             ExprKind::Match { scrutinee, scrutinee_hir_id: _, box ref arms, match_source } => {
@@ -573,9 +580,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             // and we shouldn't lint.
             // For let guards inside a match, prefixes might use bindings of the match pattern,
             // so can't always be moved out.
+            // For `else if let`, an extra indentation level would be required to move the bindings.
             // FIXME: Add checking whether the bindings are actually used in the prefix,
             // and lint if they are not.
-            if !matches!(self.let_source, LetSource::WhileLet | LetSource::IfLetGuard) {
+            if !matches!(
+                self.let_source,
+                LetSource::WhileLet | LetSource::IfLetGuard | LetSource::ElseIfLet
+            ) {
                 // Emit the lint
                 let prefix = &chain_refutabilities[..until];
                 let span_start = prefix[0].unwrap().0;
@@ -906,8 +917,8 @@ fn report_irrefutable_let_patterns(
     }
 
     match source {
-        LetSource::None | LetSource::PlainLet => bug!(),
-        LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet),
+        LetSource::None | LetSource::PlainLet | LetSource::Else => bug!(),
+        LetSource::IfLet | LetSource::ElseIfLet => emit_diag!(IrrefutableLetPatternsIfLet),
         LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard),
         LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse),
         LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet),
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 0dfa9168f7c..c89f526aa17 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -7,7 +7,7 @@ use rustc_infer::traits::Obligation;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree};
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_trait_selection::traits::ObligationCause;
@@ -36,7 +36,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         id: hir::HirId,
         span: Span,
     ) -> Box<Pat<'tcx>> {
-        let infcx = self.tcx.infer_ctxt().build();
+        // FIXME(#132279): We likely want to be able to reveal the hidden types
+        // of opaques defined in this function here.
+        let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let mut convert = ConstToPat::new(self, id, span, infcx);
         convert.to_pat(c, ty)
     }
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index 959f1ea5340..8f81da8bb04 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -7,18 +7,17 @@
 //!
 //! The `impls` module contains several examples of dataflow analyses.
 //!
-//! Create an `Engine` for your analysis using the `into_engine` method on the `Analysis` trait,
-//! then call `iterate_to_fixpoint`. From there, you can use a `ResultsCursor` to inspect the
-//! fixpoint solution to your dataflow problem, or implement the `ResultsVisitor` interface and use
-//! `visit_results`. The following example uses the `ResultsCursor` approach.
+//! Then call `iterate_to_fixpoint` on your type that impls `Analysis` to get a `Results`. From
+//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem,
+//! or implement the `ResultsVisitor` interface and use `visit_results`. The following example uses
+//! the `ResultsCursor` approach.
 //!
 //! ```ignore (cross-crate-imports)
-//! use rustc_const_eval::dataflow::Analysis; // Makes `into_engine` available.
+//! use rustc_const_eval::dataflow::Analysis; // Makes `iterate_to_fixpoint` available.
 //!
 //! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
 //!     let analysis = MyAnalysis::new()
-//!         .into_engine(tcx, body)
-//!         .iterate_to_fixpoint()
+//!         .iterate_to_fixpoint(tcx, body, None)
 //!         .into_results_cursor(body);
 //!
 //!     // Print the dataflow state *after* each statement in the start block.
@@ -34,23 +33,29 @@
 
 use std::cmp::Ordering;
 
-use rustc_index::Idx;
+use rustc_data_structures::work_queue::WorkQueue;
 use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet};
-use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges};
+use rustc_index::{Idx, IndexVec};
+use rustc_middle::bug;
+use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal};
 use rustc_middle::ty::TyCtxt;
+use tracing::error;
+
+use self::results::write_graphviz_results;
+use super::fmt::DebugWithContext;
 
 mod cursor;
 mod direction;
-mod engine;
 pub mod fmt;
 pub mod graphviz;
 pub mod lattice;
+mod results;
 mod visitor;
 
 pub use self::cursor::ResultsCursor;
 pub use self::direction::{Backward, Direction, Forward};
-pub use self::engine::{Engine, Results};
 pub use self::lattice::{JoinSemiLattice, MaybeReachable};
+pub use self::results::Results;
 pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results};
 
 /// Analysis domains are all bitsets of various kinds. This trait holds
@@ -223,26 +228,92 @@ pub trait Analysis<'tcx> {
 
     /* Extension methods */
 
-    /// Creates an `Engine` to find the fixpoint for this dataflow problem.
+    /// Finds the fixpoint for this dataflow problem.
     ///
     /// You shouldn't need to override this. Its purpose is to enable method chaining like so:
     ///
     /// ```ignore (cross-crate-imports)
     /// let results = MyAnalysis::new(tcx, body)
-    ///     .into_engine(tcx, body, def_id)
-    ///     .iterate_to_fixpoint()
+    ///     .iterate_to_fixpoint(tcx, body, None)
     ///     .into_results_cursor(body);
     /// ```
-    #[inline]
-    fn into_engine<'mir>(
-        self,
+    /// You can optionally add a `pass_name` to the graphviz output for this particular run of a
+    /// dataflow analysis. Some analyses are run multiple times in the compilation pipeline.
+    /// Without a `pass_name` to differentiates them, only the results for the latest run will be
+    /// saved.
+    fn iterate_to_fixpoint<'mir>(
+        mut self,
         tcx: TyCtxt<'tcx>,
         body: &'mir mir::Body<'tcx>,
-    ) -> Engine<'mir, 'tcx, Self>
+        pass_name: Option<&'static str>,
+    ) -> Results<'tcx, Self>
     where
         Self: Sized,
+        Self::Domain: DebugWithContext<Self>,
     {
-        Engine::new(tcx, body, self)
+        let mut entry_sets =
+            IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len());
+        self.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
+
+        if Self::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != self.bottom_value(body) {
+            bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
+        }
+
+        let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
+
+        if Self::Direction::IS_FORWARD {
+            for (bb, _) in traversal::reverse_postorder(body) {
+                dirty_queue.insert(bb);
+            }
+        } else {
+            // Reverse post-order on the reverse CFG may generate a better iteration order for
+            // backward dataflow analyses, but probably not enough to matter.
+            for (bb, _) in traversal::postorder(body) {
+                dirty_queue.insert(bb);
+            }
+        }
+
+        // `state` is not actually used between iterations;
+        // this is just an optimization to avoid reallocating
+        // every iteration.
+        let mut state = self.bottom_value(body);
+        while let Some(bb) = dirty_queue.pop() {
+            let bb_data = &body[bb];
+
+            // Set the state to the entry state of the block.
+            // This is equivalent to `state = entry_sets[bb].clone()`,
+            // but it saves an allocation, thus improving compile times.
+            state.clone_from(&entry_sets[bb]);
+
+            // Apply the block transfer function, using the cached one if it exists.
+            let edges = Self::Direction::apply_effects_in_block(&mut self, &mut state, bb, bb_data);
+
+            Self::Direction::join_state_into_successors_of(
+                &mut self,
+                body,
+                &mut state,
+                bb,
+                edges,
+                |target: BasicBlock, state: &Self::Domain| {
+                    let set_changed = entry_sets[target].join(state);
+                    if set_changed {
+                        dirty_queue.insert(target);
+                    }
+                },
+            );
+        }
+
+        let results = Results { analysis: self, entry_sets };
+
+        if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
+            let (res, results) = write_graphviz_results(tcx, body, results, pass_name);
+            if let Err(e) = res {
+                error!("Failed to write graphviz dataflow results: {}", e);
+            }
+            results
+        } else {
+            results
+        }
     }
 }
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs
index cbd1083d037..366fcbf33ba 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/results.rs
@@ -1,23 +1,19 @@
-//! A solver for dataflow problems.
+//! Dataflow analysis results.
 
 use std::ffi::OsString;
 use std::path::PathBuf;
 
-use rustc_data_structures::work_queue::WorkQueue;
 use rustc_hir::def_id::DefId;
 use rustc_index::IndexVec;
-use rustc_middle::bug;
 use rustc_middle::mir::{self, BasicBlock, create_dump_file, dump_enabled, traversal};
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_span::symbol::{Symbol, sym};
-use tracing::{debug, error};
+use tracing::debug;
 use {rustc_ast as ast, rustc_graphviz as dot};
 
 use super::fmt::DebugWithContext;
-use super::{
-    Analysis, Direction, JoinSemiLattice, ResultsCursor, ResultsVisitor, graphviz, visit_results,
-};
+use super::{Analysis, ResultsCursor, ResultsVisitor, graphviz, visit_results};
 use crate::errors::{
     DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
 };
@@ -65,124 +61,17 @@ where
         body: &'mir mir::Body<'tcx>,
         vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
     ) {
-        let blocks = mir::traversal::reachable(body);
+        let blocks = traversal::reachable(body);
         visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
     }
 }
 
-/// A solver for dataflow problems.
-pub struct Engine<'mir, 'tcx, A>
-where
-    A: Analysis<'tcx>,
-{
-    tcx: TyCtxt<'tcx>,
-    body: &'mir mir::Body<'tcx>,
-    entry_sets: IndexVec<BasicBlock, A::Domain>,
-    pass_name: Option<&'static str>,
-    analysis: A,
-}
-
-impl<'mir, 'tcx, A, D> Engine<'mir, 'tcx, A>
-where
-    A: Analysis<'tcx, Domain = D>,
-    D: Clone + JoinSemiLattice,
-{
-    /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer
-    /// function.
-    pub(crate) fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, analysis: A) -> Self {
-        let mut entry_sets =
-            IndexVec::from_fn_n(|_| analysis.bottom_value(body), body.basic_blocks.len());
-        analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
-
-        if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != analysis.bottom_value(body)
-        {
-            bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
-        }
-
-        Engine { analysis, tcx, body, pass_name: None, entry_sets }
-    }
-
-    /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis.
-    ///
-    /// Some analyses are run multiple times in the compilation pipeline. Give them a `pass_name`
-    /// to differentiate them. Otherwise, only the results for the latest run will be saved.
-    pub fn pass_name(mut self, name: &'static str) -> Self {
-        self.pass_name = Some(name);
-        self
-    }
-
-    /// Computes the fixpoint for this dataflow problem and returns it.
-    pub fn iterate_to_fixpoint(self) -> Results<'tcx, A>
-    where
-        A::Domain: DebugWithContext<A>,
-    {
-        let Engine { mut analysis, body, mut entry_sets, tcx, pass_name } = self;
-
-        let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
-
-        if A::Direction::IS_FORWARD {
-            for (bb, _) in traversal::reverse_postorder(body) {
-                dirty_queue.insert(bb);
-            }
-        } else {
-            // Reverse post-order on the reverse CFG may generate a better iteration order for
-            // backward dataflow analyses, but probably not enough to matter.
-            for (bb, _) in traversal::postorder(body) {
-                dirty_queue.insert(bb);
-            }
-        }
-
-        // `state` is not actually used between iterations;
-        // this is just an optimization to avoid reallocating
-        // every iteration.
-        let mut state = analysis.bottom_value(body);
-        while let Some(bb) = dirty_queue.pop() {
-            let bb_data = &body[bb];
-
-            // Set the state to the entry state of the block.
-            // This is equivalent to `state = entry_sets[bb].clone()`,
-            // but it saves an allocation, thus improving compile times.
-            state.clone_from(&entry_sets[bb]);
-
-            // Apply the block transfer function, using the cached one if it exists.
-            let edges =
-                A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data);
-
-            A::Direction::join_state_into_successors_of(
-                &mut analysis,
-                body,
-                &mut state,
-                bb,
-                edges,
-                |target: BasicBlock, state: &A::Domain| {
-                    let set_changed = entry_sets[target].join(state);
-                    if set_changed {
-                        dirty_queue.insert(target);
-                    }
-                },
-            );
-        }
-
-        let results = Results { analysis, entry_sets };
-
-        if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
-            let (res, results) = write_graphviz_results(tcx, body, results, pass_name);
-            if let Err(e) = res {
-                error!("Failed to write graphviz dataflow results: {}", e);
-            }
-            results
-        } else {
-            results
-        }
-    }
-}
-
 // Graphviz
 
 /// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
 /// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are
 /// the same.
-fn write_graphviz_results<'tcx, A>(
+pub(super) fn write_graphviz_results<'tcx, A>(
     tcx: TyCtxt<'tcx>,
     body: &mir::Body<'tcx>,
     results: Results<'tcx, A>,
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index b284f0308f9..b404e3bfb72 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -18,9 +18,9 @@ pub use self::drop_flag_effects::{
     move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
 };
 pub use self::framework::{
-    Analysis, Backward, Direction, Engine, Forward, GenKill, JoinSemiLattice, MaybeReachable,
-    Results, ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz,
-    lattice, visit_results,
+    Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results,
+    ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
+    visit_results,
 };
 use self::move_paths::MoveData;
 
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 5727517bd61..99d0ccde105 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -43,31 +43,28 @@ pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
     let move_data = MoveData::gather_moves(body, tcx, |_| true);
 
     if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
-        let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
-            .into_engine(tcx, body)
-            .iterate_to_fixpoint();
+        let flow_inits =
+            MaybeInitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(tcx, body, None);
 
         sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
     }
 
     if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
         let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
-            .into_engine(tcx, body)
-            .iterate_to_fixpoint();
+            .iterate_to_fixpoint(tcx, body, None);
 
         sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
     }
 
     if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
-        let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data)
-            .into_engine(tcx, body)
-            .iterate_to_fixpoint();
+        let flow_def_inits =
+            DefinitelyInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(tcx, body, None);
 
         sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
     }
 
     if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
-        let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
+        let flow_liveness = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None);
 
         sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
     }
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index cd291058977..6d5665b4331 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -64,7 +64,7 @@ use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{
-    self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt,
+    self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_mir_dataflow::Analysis;
@@ -666,14 +666,13 @@ fn locals_live_across_suspend_points<'tcx>(
     // Calculate when MIR locals have live storage. This gives us an upper bound of their
     // lifetimes.
     let mut storage_live = MaybeStorageLive::new(std::borrow::Cow::Borrowed(always_live_locals))
-        .into_engine(tcx, body)
-        .iterate_to_fixpoint()
+        .iterate_to_fixpoint(tcx, body, None)
         .into_results_cursor(body);
 
     // Calculate the MIR locals which have been previously
     // borrowed (even if they are still active).
     let borrowed_locals_results =
-        MaybeBorrowedLocals.into_engine(tcx, body).pass_name("coroutine").iterate_to_fixpoint();
+        MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine"));
 
     let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body);
 
@@ -681,16 +680,12 @@ fn locals_live_across_suspend_points<'tcx>(
     // for.
     let mut requires_storage_cursor =
         MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body))
-            .into_engine(tcx, body)
-            .iterate_to_fixpoint()
+            .iterate_to_fixpoint(tcx, body, None)
             .into_results_cursor(body);
 
     // Calculate the liveness of MIR locals ignoring borrows.
-    let mut liveness = MaybeLiveLocals
-        .into_engine(tcx, body)
-        .pass_name("coroutine")
-        .iterate_to_fixpoint()
-        .into_results_cursor(body);
+    let mut liveness =
+        MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")).into_results_cursor(body);
 
     let mut storage_liveness_map = IndexVec::from_elem(None, &body.basic_blocks);
     let mut live_locals_at_suspension_points = Vec::new();
@@ -1501,7 +1496,11 @@ fn check_field_tys_sized<'tcx>(
         return;
     }
 
-    let infcx = tcx.infer_ctxt().ignoring_regions().build();
+    // FIXME(#132279): @lcnr believes that we may want to support coroutines
+    // whose `Sized`-ness relies on the hidden types of opaques defined by the
+    // parent function. In this case we'd have to be able to reveal only these
+    // opaques here.
+    let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
     let param_env = tcx.param_env(def_id);
 
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 002216f50f2..07263460733 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -59,7 +59,7 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
         // Perform the actual dataflow analysis.
         let analysis = ConstAnalysis::new(tcx, body, map);
         let mut results = debug_span!("analyze")
-            .in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint());
+            .in_scope(|| analysis.wrap().iterate_to_fixpoint(tcx, body, None));
 
         // Collect results and patch the body afterwards.
         let mut visitor = Collector::new(tcx, &body.local_decls);
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index edffe6ce78f..2898f82e25c 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -37,8 +37,7 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     always_live.union(&borrowed_locals);
 
     let mut live = MaybeTransitiveLiveLocals::new(&always_live)
-        .into_engine(tcx, body)
-        .iterate_to_fixpoint()
+        .iterate_to_fixpoint(tcx, body, None)
         .into_results_cursor(body);
 
     // For blocks with a call terminator, if an argument copy can be turned into a move,
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index ad83c0295ba..beeab0d4a66 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -169,10 +169,7 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
 
         let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body);
 
-        let live = MaybeLiveLocals
-            .into_engine(tcx, body)
-            .pass_name("MaybeLiveLocals-DestinationPropagation")
-            .iterate_to_fixpoint();
+        let live = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("MaybeLiveLocals-DestProp"));
         let points = DenseLocationMap::new(body);
         let mut live = save_as_intervals(&points, body, live);
 
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index 30e1ac05e03..58e1db19438 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -64,18 +64,14 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops {
 
             let mut inits = MaybeInitializedPlaces::new(tcx, body, &env.move_data)
                 .skipping_unreachable_unwind()
-                .into_engine(tcx, body)
-                .pass_name("elaborate_drops")
-                .iterate_to_fixpoint()
+                .iterate_to_fixpoint(tcx, body, Some("elaborate_drops"))
                 .into_results_cursor(body);
             let dead_unwinds = compute_dead_unwinds(body, &mut inits);
 
             let uninits = MaybeUninitializedPlaces::new(tcx, body, &env.move_data)
                 .mark_inactive_variants_as_uninit()
                 .skipping_unreachable_unwind(dead_unwinds)
-                .into_engine(tcx, body)
-                .pass_name("elaborate_drops")
-                .iterate_to_fixpoint()
+                .iterate_to_fixpoint(tcx, body, Some("elaborate_drops"))
                 .into_results_cursor(body);
 
             let drop_flags = IndexVec::from_elem(None, &env.move_data.move_paths);
diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs
index 23733994a8b..d8ff1cfc90b 100644
--- a/compiler/rustc_mir_transform/src/lint.rs
+++ b/compiler/rustc_mir_transform/src/lint.rs
@@ -17,13 +17,11 @@ pub(super) fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String
     let always_live_locals = &always_storage_live_locals(body);
 
     let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals))
-        .into_engine(tcx, body)
-        .iterate_to_fixpoint()
+        .iterate_to_fixpoint(tcx, body, None)
         .into_results_cursor(body);
 
     let maybe_storage_dead = MaybeStorageDead::new(Cow::Borrowed(always_live_locals))
-        .into_engine(tcx, body)
-        .iterate_to_fixpoint()
+        .iterate_to_fixpoint(tcx, body, None)
         .into_results_cursor(body);
 
     let mut lint = Lint {
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index 53e53d9d5ba..b11b503e8d4 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -126,8 +126,7 @@ fn compute_replacement<'tcx>(
     // Compute `MaybeStorageDead` dataflow to check that we only replace when the pointee is
     // definitely live.
     let mut maybe_dead = MaybeStorageDead::new(Cow::Owned(always_live_locals))
-        .into_engine(tcx, body)
-        .iterate_to_fixpoint()
+        .iterate_to_fixpoint(tcx, body, None)
         .into_results_cursor(body);
 
     // Map for each local to the pointee.
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
index 09969a4c7cc..55dd96100b0 100644
--- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -22,9 +22,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
         let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, param_env));
 
         let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
-            .into_engine(tcx, body)
-            .pass_name("remove_uninit_drops")
-            .iterate_to_fixpoint()
+            .iterate_to_fixpoint(tcx, body, Some("remove_uninit_drops"))
             .into_results_cursor(body);
 
         let mut to_remove = vec![];
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 25e68f44456..77356723c46 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -12,7 +12,7 @@ use rustc_middle::mir::*;
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::{
     self, CoroutineArgsExt, InstanceKind, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
-    Variance,
+    TypingMode, Variance,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_target::abi::{FIRST_VARIANT, Size};
@@ -606,7 +606,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             return true;
         }
 
-        let infcx = self.tcx.infer_ctxt().build();
+        let infcx = self.tcx.infer_ctxt().build(TypingMode::from_param_env(self.param_env));
         let ocx = ObligationCtxt::new(&infcx);
         ocx.register_obligation(Obligation::new(
             self.tcx,
diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs
index 4da1e7fa711..f7fbfed5b8e 100644
--- a/compiler/rustc_next_trait_solver/src/delegate.rs
+++ b/compiler/rustc_next_trait_solver/src/delegate.rs
@@ -1,7 +1,7 @@
 use std::ops::Deref;
 
 use rustc_type_ir::fold::TypeFoldable;
-use rustc_type_ir::solve::{Certainty, Goal, NoSolution, SolverMode};
+use rustc_type_ir::solve::{Certainty, Goal, NoSolution};
 use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
 
 pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Sized {
@@ -15,7 +15,6 @@ pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Size
 
     fn build_with_canonical<V>(
         cx: Self::Interner,
-        solver_mode: SolverMode,
         canonical: &ty::CanonicalQueryInput<Self::Interner, V>,
     ) -> (Self, V, ty::CanonicalVarValues<Self::Interner>)
     where
@@ -93,7 +92,6 @@ pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Size
 
     fn fetch_eligible_assoc_item(
         &self,
-        param_env: <Self::Interner as Interner>::ParamEnv,
         goal_trait_ref: ty::TraitRef<Self::Interner>,
         trait_assoc_def_id: <Self::Interner as Interner>::DefId,
         impl_def_id: <Self::Interner as Interner>::DefId,
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index f6a5f20a639..ebf7372926f 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -8,14 +8,14 @@ use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::solve::inspect;
 use rustc_type_ir::visit::TypeVisitableExt as _;
-use rustc_type_ir::{self as ty, Interner, Upcast as _, elaborate};
+use rustc_type_ir::{self as ty, Interner, TypingMode, Upcast as _, elaborate};
 use tracing::{debug, instrument};
 
 use crate::delegate::SolverDelegate;
 use crate::solve::inspect::ProbeKind;
 use crate::solve::{
     BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource,
-    MaybeCause, NoSolution, QueryResult, SolverMode,
+    MaybeCause, NoSolution, QueryResult,
 };
 
 /// A candidate is a possible way to prove a goal.
@@ -328,11 +328,12 @@ where
 
         let mut candidates = vec![];
 
-        if self.solver_mode() == SolverMode::Coherence {
+        if let TypingMode::Coherence = self.typing_mode(goal.param_env) {
             if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) {
                 return vec![candidate];
             }
         }
+
         self.assemble_impl_candidates(goal, &mut candidates);
 
         self.assemble_builtin_impl_candidates(goal, &mut candidates);
@@ -343,8 +344,11 @@ where
 
         self.assemble_param_env_candidates(goal, &mut candidates);
 
-        if self.solver_mode() == SolverMode::Normal {
-            self.discard_impls_shadowed_by_env(goal, &mut candidates);
+        match self.typing_mode(goal.param_env) {
+            TypingMode::Coherence => {}
+            TypingMode::Analysis { .. } | TypingMode::PostAnalysis => {
+                self.discard_impls_shadowed_by_env(goal, &mut candidates);
+            }
         }
 
         candidates
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
index e2fd0dd2a25..2f50070d438 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
@@ -55,6 +55,7 @@ where
         &self,
         goal: Goal<I, T>,
     ) -> (Vec<I::GenericArg>, CanonicalInput<I, T>) {
+        let param_env_for_debug_assertion = goal.param_env;
         let opaque_types = self.delegate.clone_opaque_types_for_query_response();
         let (goal, opaque_types) =
             (goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate));
@@ -73,7 +74,7 @@ where
         );
         let query_input = ty::CanonicalQueryInput {
             canonical,
-            defining_opaque_types: self.delegate.defining_opaque_types(),
+            typing_mode: self.typing_mode(param_env_for_debug_assertion),
         };
         (orig_values, query_input)
     }
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index 7608253882a..8685896715e 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -10,7 +10,7 @@ use rustc_type_ir::inherent::*;
 use rustc_type_ir::relate::Relate;
 use rustc_type_ir::relate::solver_relating::RelateExt;
 use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
-use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner};
+use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner, TypingMode};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 use tracing::{instrument, trace};
 
@@ -21,7 +21,6 @@ use crate::solve::search_graph::SearchGraph;
 use crate::solve::{
     CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, GoalSource,
     HasChanged, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult,
-    SolverMode,
 };
 
 pub(super) mod canonical;
@@ -215,8 +214,8 @@ where
     D: SolverDelegate<Interner = I>,
     I: Interner,
 {
-    pub(super) fn solver_mode(&self) -> SolverMode {
-        self.search_graph.solver_mode()
+    pub(super) fn typing_mode(&self, param_env_for_debug_assertion: I::ParamEnv) -> TypingMode<I> {
+        self.delegate.typing_mode(param_env_for_debug_assertion)
     }
 
     pub(super) fn set_is_normalizes_to_goal(&mut self) {
@@ -232,7 +231,7 @@ where
         generate_proof_tree: GenerateProofTree,
         f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R,
     ) -> (R, Option<inspect::GoalEvaluation<I>>) {
-        let mut search_graph = SearchGraph::new(delegate.solver_mode(), root_depth);
+        let mut search_graph = SearchGraph::new(root_depth);
 
         let mut ecx = EvalCtxt {
             delegate,
@@ -279,7 +278,7 @@ where
         f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R,
     ) -> R {
         let (ref delegate, input, var_values) =
-            SolverDelegate::build_with_canonical(cx, search_graph.solver_mode(), &canonical_input);
+            SolverDelegate::build_with_canonical(cx, &canonical_input);
 
         let mut ecx = EvalCtxt {
             delegate,
@@ -942,21 +941,11 @@ where
 
     pub(super) fn fetch_eligible_assoc_item(
         &self,
-        param_env: I::ParamEnv,
         goal_trait_ref: ty::TraitRef<I>,
         trait_assoc_def_id: I::DefId,
         impl_def_id: I::DefId,
     ) -> Result<Option<I::DefId>, NoSolution> {
-        self.delegate.fetch_eligible_assoc_item(
-            param_env,
-            goal_trait_ref,
-            trait_assoc_def_id,
-            impl_def_id,
-        )
-    }
-
-    pub(super) fn can_define_opaque_ty(&self, def_id: I::LocalDefId) -> bool {
-        self.delegate.defining_opaque_types().contains(&def_id)
+        self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id)
     }
 
     pub(super) fn insert_hidden_type(
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 7287cdf74bf..129744b4db7 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -6,7 +6,7 @@ mod weak_types;
 use rustc_type_ir::fast_reject::DeepRejectCtxt;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
-use rustc_type_ir::{self as ty, Interner, NormalizesTo, Upcast as _};
+use rustc_type_ir::{self as ty, Interner, NormalizesTo, TypingMode, Upcast as _};
 use tracing::instrument;
 
 use crate::delegate::SolverDelegate;
@@ -15,7 +15,7 @@ use crate::solve::assembly::{self, Candidate};
 use crate::solve::inspect::ProbeKind;
 use crate::solve::{
     BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
-    NoSolution, QueryResult, Reveal,
+    NoSolution, QueryResult,
 };
 
 impl<D, I> EvalCtxt<'_, D>
@@ -71,21 +71,21 @@ where
                 Ok(())
             }
             ty::AliasTermKind::OpaqueTy => {
-                match param_env.reveal() {
-                    // In user-facing mode, paques are only rigid if we may not define it.
-                    Reveal::UserFacing => {
+                match self.typing_mode(param_env) {
+                    // Opaques are never rigid outside of analysis mode.
+                    TypingMode::Coherence | TypingMode::PostAnalysis => Err(NoSolution),
+                    // During analysis, opaques are only rigid if we may not define it.
+                    TypingMode::Analysis { defining_opaque_types } => {
                         if rigid_alias
                             .def_id
                             .as_local()
-                            .is_some_and(|def_id| self.can_define_opaque_ty(def_id))
+                            .is_some_and(|def_id| defining_opaque_types.contains(&def_id))
                         {
                             Err(NoSolution)
                         } else {
                             Ok(())
                         }
                     }
-                    // Opaques are never rigid in reveal-all mode.
-                    Reveal::All => Err(NoSolution),
                 }
             }
             // FIXME(generic_const_exprs): we would need to support generic consts here
@@ -252,7 +252,6 @@ where
             // return ambiguity this would otherwise be incomplete, resulting in
             // unsoundness during coherence (#105782).
             let Some(target_item_def_id) = ecx.fetch_eligible_assoc_item(
-                goal.param_env,
                 goal_trait_ref,
                 goal.predicate.def_id(),
                 impl_def_id,
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
index f8d51f304f3..d1d701695ab 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
@@ -4,12 +4,10 @@
 
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_type_ir::inherent::*;
-use rustc_type_ir::{self as ty, Interner};
+use rustc_type_ir::{self as ty, Interner, TypingMode};
 
 use crate::delegate::SolverDelegate;
-use crate::solve::{
-    Certainty, EvalCtxt, Goal, NoSolution, QueryResult, Reveal, SolverMode, inspect,
-};
+use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, inspect};
 
 impl<D, I> EvalCtxt<'_, D>
 where
@@ -24,17 +22,27 @@ where
         let opaque_ty = goal.predicate.alias;
         let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const");
 
-        match (goal.param_env.reveal(), self.solver_mode()) {
-            (Reveal::UserFacing, SolverMode::Normal) => {
-                let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else {
+        match self.typing_mode(goal.param_env) {
+            TypingMode::Coherence => {
+                // An impossible opaque type bound is the only way this goal will fail
+                // e.g. assigning `impl Copy := NotCopy`
+                self.add_item_bounds_for_hidden_type(
+                    opaque_ty.def_id,
+                    opaque_ty.args,
+                    goal.param_env,
+                    expected,
+                );
+                self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+            }
+            TypingMode::Analysis { defining_opaque_types } => {
+                let Some(def_id) = opaque_ty.def_id.as_local() else {
                     return Err(NoSolution);
                 };
-                // FIXME: at some point we should call queries without defining
-                // new opaque types but having the existing opaque type definitions.
-                // This will require moving this below "Prefer opaques registered already".
-                if !self.can_define_opaque_ty(opaque_ty_def_id) {
+
+                if !defining_opaque_types.contains(&def_id) {
                     return Err(NoSolution);
                 }
+
                 // FIXME: This may have issues when the args contain aliases...
                 match uses_unique_placeholders_ignoring_regions(self.cx(), opaque_ty.args) {
                     Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => {
@@ -48,8 +56,7 @@ where
                     Ok(()) => {}
                 }
                 // Prefer opaques registered already.
-                let opaque_type_key =
-                    ty::OpaqueTypeKey { def_id: opaque_ty_def_id, args: opaque_ty.args };
+                let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args };
                 // FIXME: This also unifies the previous hidden type with the expected.
                 //
                 // If that fails, we insert `expected` as a new hidden type instead of
@@ -69,7 +76,7 @@ where
                             }
                             ecx.eq(goal.param_env, candidate_ty, expected)?;
                             ecx.add_item_bounds_for_hidden_type(
-                                candidate_key.def_id.into(),
+                                def_id.into(),
                                 candidate_key.args,
                                 goal.param_env,
                                 candidate_ty,
@@ -82,25 +89,14 @@ where
                 // FIXME: should we use `inject_hidden_type_unchecked` here?
                 self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;
                 self.add_item_bounds_for_hidden_type(
-                    opaque_ty.def_id,
+                    def_id.into(),
                     opaque_ty.args,
                     goal.param_env,
                     expected,
                 );
                 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             }
-            (Reveal::UserFacing, SolverMode::Coherence) => {
-                // An impossible opaque type bound is the only way this goal will fail
-                // e.g. assigning `impl Copy := NotCopy`
-                self.add_item_bounds_for_hidden_type(
-                    opaque_ty.def_id,
-                    opaque_ty.args,
-                    goal.param_env,
-                    expected,
-                );
-                self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
-            }
-            (Reveal::All, _) => {
+            TypingMode::PostAnalysis => {
                 // FIXME: Add an assertion that opaque type storage is empty.
                 let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args);
                 self.eq(goal.param_env, expected, actual)?;
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 08cc89d950e..e23e475a2a6 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -6,7 +6,7 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::visit::TypeVisitableExt as _;
-use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _, elaborate};
+use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate};
 use tracing::{instrument, trace};
 
 use crate::delegate::SolverDelegate;
@@ -15,7 +15,7 @@ use crate::solve::assembly::{self, Candidate};
 use crate::solve::inspect::ProbeKind;
 use crate::solve::{
     BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
-    NoSolution, QueryResult, Reveal, SolverMode,
+    NoSolution, QueryResult,
 };
 
 impl<D, I> assembly::GoalKind<D> for TraitPredicate<I>
@@ -67,9 +67,9 @@ where
         let maximal_certainty = match (impl_polarity, goal.predicate.polarity) {
             // In intercrate mode, this is ambiguous. But outside of intercrate,
             // it's not a real impl.
-            (ty::ImplPolarity::Reservation, _) => match ecx.solver_mode() {
-                SolverMode::Coherence => Certainty::AMBIGUOUS,
-                SolverMode::Normal => return Err(NoSolution),
+            (ty::ImplPolarity::Reservation, _) => match ecx.typing_mode(goal.param_env) {
+                TypingMode::Coherence => Certainty::AMBIGUOUS,
+                TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Err(NoSolution),
             },
 
             // Impl matches polarity
@@ -167,30 +167,26 @@ where
             return result;
         }
 
-        // Don't call `type_of` on a local TAIT that's in the defining scope,
-        // since that may require calling `typeck` on the same item we're
+        // We only look into opaque types during analysis for opaque types
+        // outside of their defining scope. Doing so for opaques in the
+        // defining scope may require calling `typeck` on the same item we're
         // currently type checking, which will result in a fatal cycle that
         // ideally we want to avoid, since we can make progress on this goal
         // via an alias bound or a locally-inferred hidden type instead.
-        //
-        // Also, don't call `type_of` on a TAIT in `Reveal::All` mode, since
-        // we already normalize the self type in
-        // `assemble_candidates_after_normalizing_self_ty`, and we'd
-        // just be registering an identical candidate here.
-        //
-        // We always return `Err(NoSolution)` here in `SolverMode::Coherence`
-        // since we'll always register an ambiguous candidate in
-        // `assemble_candidates_after_normalizing_self_ty` due to normalizing
-        // the TAIT.
         if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
-            if matches!(goal.param_env.reveal(), Reveal::All)
-                || matches!(ecx.solver_mode(), SolverMode::Coherence)
-                || opaque_ty
-                    .def_id
-                    .as_local()
-                    .is_some_and(|def_id| ecx.can_define_opaque_ty(def_id))
-            {
-                return Err(NoSolution);
+            match ecx.typing_mode(goal.param_env) {
+                TypingMode::Coherence | TypingMode::PostAnalysis => {
+                    unreachable!("rigid opaque outside of analysis: {goal:?}");
+                }
+                TypingMode::Analysis { defining_opaque_types } => {
+                    if opaque_ty
+                        .def_id
+                        .as_local()
+                        .is_some_and(|def_id| defining_opaque_types.contains(&def_id))
+                    {
+                        return Err(NoSolution);
+                    }
+                }
             }
         }
 
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 77ad4fdeeb1..50a8b6542df 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -424,7 +424,7 @@ impl TokenDescription {
     }
 }
 
-pub(super) fn token_descr(token: &Token) -> String {
+pub fn token_descr(token: &Token) -> String {
     let name = pprust::token_to_string(token).to_string();
 
     let kind = match (TokenDescription::from_token(token), &token.kind) {
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 8c4592cbb36..0a2926c0404 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -25,7 +25,7 @@ use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::{
     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
@@ -2267,7 +2267,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let def_id = hir_id.expect_owner().def_id;
         let param_env = ty::ParamEnv::empty();
 
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
         let span = tcx.def_span(def_id);
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 0b6cf82ca8b..921a915d05b 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -2,6 +2,7 @@ use rustc_abi::{HasDataLayout, TargetDataLayout};
 use rustc_ast::Attribute;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
+use rustc_middle::infer::canonical::ir::TypingMode;
 use rustc_middle::span_bug;
 use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers};
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
@@ -54,7 +55,7 @@ pub fn ensure_wf<'tcx>(
         param_env,
         pred,
     );
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
     let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
     ocx.register_obligation(obligation);
     let errors = ocx.select_all_or_error();
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index 5793ac2fc31..c53689b211d 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -7,13 +7,13 @@ use rustc_infer::infer::canonical::{
     Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
 };
 use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
+use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::solve::Goal;
-use rustc_infer::traits::{ObligationCause, Reveal};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
-use rustc_type_ir::solve::{Certainty, NoSolution, SolverMode};
-use tracing::trace;
+use rustc_type_ir::TypingMode;
+use rustc_type_ir::solve::{Certainty, NoSolution};
 
 use crate::traits::specialization_graph;
 
@@ -47,7 +47,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
 
     fn build_with_canonical<V>(
         interner: TyCtxt<'tcx>,
-        solver_mode: SolverMode,
         canonical: &CanonicalQueryInput<'tcx, V>,
     ) -> (Self, V, CanonicalVarValues<'tcx>)
     where
@@ -56,10 +55,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         let (infcx, value, vars) = interner
             .infer_ctxt()
             .with_next_trait_solver(true)
-            .intercrate(match solver_mode {
-                SolverMode::Normal => false,
-                SolverMode::Coherence => true,
-            })
             .build_with_canonical(DUMMY_SP, canonical);
         (SolverDelegate(infcx), value, vars)
     }
@@ -195,7 +190,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
 
     fn fetch_eligible_assoc_item(
         &self,
-        param_env: ty::ParamEnv<'tcx>,
         goal_trait_ref: ty::TraitRef<'tcx>,
         trait_assoc_def_id: DefId,
         impl_def_id: DefId,
@@ -211,12 +205,12 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
             // and the obligation is monomorphic, otherwise passes such as
             // transmute checking and polymorphic MIR optimizations could
             // get a result which isn't correct for all monomorphizations.
-            if param_env.reveal() == Reveal::All {
-                let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
-                !poly_trait_ref.still_further_specializable()
-            } else {
-                trace!(?node_item.item.def_id, "not eligible due to default");
-                false
+            match self.typing_mode_unchecked() {
+                TypingMode::Coherence | TypingMode::Analysis { .. } => false,
+                TypingMode::PostAnalysis => {
+                    let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
+                    !poly_trait_ref.still_further_specializable()
+                }
             }
         };
 
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 934fe9ec47c..52ba5621d31 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -10,6 +10,7 @@ use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::{Region, RegionVid};
 use tracing::debug;
+use ty::TypingMode;
 
 use super::*;
 use crate::errors::UnableToConstructConstantValue;
@@ -79,7 +80,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
 
         let trait_ref = ty::TraitRef::new(tcx, trait_did, [ty]);
 
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let mut selcx = SelectionContext::new(&infcx);
         for polarity in [ty::PredicatePolarity::Positive, ty::PredicatePolarity::Negative] {
             let result = selcx.select(&Obligation::new(
@@ -99,7 +100,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
             }
         }
 
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let mut fresh_preds = FxIndexSet::default();
 
         // Due to the way projections are handled by SelectionContext, we need to run
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index f8fb297e36c..3cd11d7c8e8 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -18,7 +18,7 @@ use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
 use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
 pub use rustc_next_trait_solver::coherence::*;
 use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
 use rustc_span::symbol::sym;
@@ -195,9 +195,8 @@ fn overlap<'tcx>(
     let infcx = tcx
         .infer_ctxt()
         .skip_leak_check(skip_leak_check.is_yes())
-        .intercrate(true)
         .with_next_trait_solver(tcx.next_trait_solver_in_coherence())
-        .build();
+        .build(TypingMode::Coherence);
     let selcx = &mut SelectionContext::new(&infcx);
     if track_ambiguity_causes.is_yes() {
         selcx.enable_tracking_intercrate_ambiguity_causes();
@@ -419,7 +418,7 @@ fn impl_intersection_has_negative_obligation(
 
     // N.B. We need to unify impl headers *with* intercrate mode, even if proving negative predicates
     // do not need intercrate mode enabled.
-    let ref infcx = tcx.infer_ctxt().intercrate(true).with_next_trait_solver(true).build();
+    let ref infcx = tcx.infer_ctxt().with_next_trait_solver(true).build(TypingMode::Coherence);
     let root_universe = infcx.universe();
     assert_eq!(root_universe, ty::UniverseIndex::ROOT);
 
@@ -570,7 +569,9 @@ fn try_prove_negated_where_clause<'tcx>(
     // the *existence* of a negative goal, not the non-existence of a positive goal.
     // Without this, we over-eagerly register coherence ambiguity candidates when
     // impl candidates do exist.
-    let ref infcx = root_infcx.fork_with_intercrate(false);
+    // FIXME(#132279): `TypingMode::non_body_analysis` is a bit questionable here as it
+    // would cause us to reveal opaque types to leak their auto traits.
+    let ref infcx = root_infcx.fork_with_typing_mode(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new(infcx);
     ocx.register_obligation(Obligation::new(
         infcx.tcx,
@@ -714,7 +715,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
 
             // It is only relevant that a goal is unknowable if it would have otherwise
             // failed.
-            let non_intercrate_infcx = infcx.fork_with_intercrate(false);
+            // FIXME(#132279): Forking with `TypingMode::non_body_analysis` is a bit questionable
+            // as it would allow us to reveal opaque types, potentially causing unexpected
+            // cycles.
+            let non_intercrate_infcx = infcx.fork_with_typing_mode(TypingMode::non_body_analysis());
             if non_intercrate_infcx.predicate_may_hold(&Obligation::new(
                 infcx.tcx,
                 ObligationCause::dummy(),
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index a068f25fe35..bd4e3dd7d8d 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -14,7 +14,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::{
     self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt,
     TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt, TypeVisitor, Upcast,
+    TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
 };
 use rustc_span::Span;
 use rustc_span::symbol::Symbol;
@@ -718,7 +718,7 @@ fn receiver_is_dispatchable<'tcx>(
         Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
     };
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     // the receiver is dispatchable iff the obligation holds
     infcx.predicate_must_hold_modulo_regions(&obligation)
 }
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs
index bd8c04b7655..60b3357810a 100644
--- a/compiler/rustc_trait_selection/src/traits/effects.rs
+++ b/compiler/rustc_trait_selection/src/traits/effects.rs
@@ -1,8 +1,9 @@
 use rustc_hir as hir;
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt};
 use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation};
+use rustc_middle::span_bug;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
-use rustc_middle::{span_bug, ty};
+use rustc_middle::ty::{self, TypingMode};
 use rustc_type_ir::solve::NoSolution;
 use thin_vec::ThinVec;
 
@@ -19,7 +20,7 @@ pub fn evaluate_host_effect_obligation<'tcx>(
     selcx: &mut SelectionContext<'_, 'tcx>,
     obligation: &HostEffectObligation<'tcx>,
 ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
-    if selcx.infcx.intercrate {
+    if matches!(selcx.infcx.typing_mode(obligation.param_env), TypingMode::Coherence) {
         span_bug!(
             obligation.cause.span,
             "should not select host obligation in old solver in intercrate mode"
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index e3ad21e352a..29e60e3c428 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -13,7 +13,7 @@ use rustc_middle::bug;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt};
+use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode};
 use thin_vec::ThinVec;
 use tracing::{debug, debug_span, instrument};
 
@@ -760,7 +760,9 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
         stalled_on: &mut Vec<TyOrConstInferVar>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let infcx = self.selcx.infcx;
-        if obligation.predicate.is_global() && !self.selcx.is_intercrate() {
+        if obligation.predicate.is_global()
+            && !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
+        {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
             if infcx.predicate_must_hold_considering_regions(obligation) {
@@ -813,11 +815,13 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
         stalled_on: &mut Vec<TyOrConstInferVar>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let tcx = self.selcx.tcx();
-
-        if obligation.predicate.is_global() && !self.selcx.is_intercrate() {
+        let infcx = self.selcx.infcx;
+        if obligation.predicate.is_global()
+            && !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
+        {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
-            if self.selcx.infcx.predicate_must_hold_considering_regions(obligation) {
+            if infcx.predicate_must_hold_considering_regions(obligation) {
                 if let Some(key) = ProjectionCacheKey::from_poly_projection_obligation(
                     &mut self.selcx,
                     &project_obligation,
@@ -825,8 +829,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
                     // If `predicate_must_hold_considering_regions` succeeds, then we've
                     // evaluated all sub-obligations. We can therefore mark the 'root'
                     // obligation as complete, and skip evaluating sub-obligations.
-                    self.selcx
-                        .infcx
+                    infcx
                         .inner
                         .borrow_mut()
                         .projection_cache()
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index 3e65194577e..3b17fa6b032 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
-use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
 
 use super::outlives_bounds::InferCtxtExt;
 use crate::regions::InferCtxtRegionExt;
@@ -143,7 +143,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
     let mut infringing_inner_tys = vec![];
     for inner_ty in inner_tys {
         // We use an ocx per inner ty for better diagnostics
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
 
         ocx.register_bound(
@@ -200,7 +200,7 @@ pub fn all_fields_implement_trait<'tcx>(
     for variant in adt.variants() {
         for field in &variant.fields {
             // Do this per-field to get better error messages.
-            let infcx = tcx.infer_ctxt().build();
+            let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
             let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
 
             let unnormalized_ty = field.ty(tcx, args);
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index f5d9b50359c..1c84f2171bc 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -34,7 +34,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::{
-    self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, Upcast,
+    self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, TypingMode,
+    Upcast,
 };
 use rustc_span::Span;
 use rustc_span::def_id::DefId;
@@ -274,7 +275,7 @@ fn do_normalize_predicates<'tcx>(
     // by wfcheck anyway, so I'm not sure we have to check
     // them here too, and we will remove this function when
     // we move over to lazy normalization *anyway*.
-    let infcx = tcx.infer_ctxt().ignoring_regions().build();
+    let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
     let predicates = ocx.normalize(&cause, elaborated_env, predicates);
 
@@ -475,11 +476,11 @@ pub fn normalize_param_env_or_error<'tcx>(
 
 /// Normalizes the predicates and checks whether they hold in an empty environment. If this
 /// returns true, then either normalize encountered an error or one of the predicates did not
-/// hold. Used when creating vtables to check for unsatisfiable methods.
+/// hold. Used when creating vtables to check for unsatisfiable methods. This should not be
+/// used during analysis.
 pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec<ty::Clause<'tcx>>) -> bool {
     debug!("impossible_predicates(predicates={:?})", predicates);
-
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
     let param_env = ty::ParamEnv::reveal_all();
     let ocx = ObligationCtxt::new(&infcx);
     let predicates = ocx.normalize(&ObligationCause::dummy(), param_env, predicates);
@@ -568,8 +569,11 @@ fn is_impossible_associated_item(
     // since that method *may* have some substitutions where the predicates hold.
     //
     // This replicates the logic we use in coherence.
-    let infcx =
-        tcx.infer_ctxt().ignoring_regions().with_next_trait_solver(true).intercrate(true).build();
+    let infcx = tcx
+        .infer_ctxt()
+        .ignoring_regions()
+        .with_next_trait_solver(true)
+        .build(TypingMode::Coherence);
     let param_env = ty::ParamEnv::empty();
     let fresh_args = infcx.fresh_args_for_item(tcx.def_span(impl_def_id), impl_def_id);
 
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 0803dd74b89..a75c07c2e8c 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -334,11 +334,6 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
 ) -> Result<Option<Term<'tcx>>, InProgress> {
     let infcx = selcx.infcx;
     debug_assert!(!selcx.infcx.next_trait_solver());
-    // Don't use the projection cache in intercrate mode -
-    // the `infcx` may be re-used between intercrate in non-intercrate
-    // mode, which could lead to using incorrect cache results.
-    let use_cache = !selcx.is_intercrate();
-
     let projection_term = infcx.resolve_vars_if_possible(projection_term);
     let cache_key = ProjectionCacheKey::new(projection_term, param_env);
 
@@ -349,13 +344,8 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
     // would not benefit from caching when proving `T: Trait<U=Foo>`
     // bounds. It might be the case that we want two distinct caches,
     // or else another kind of cache entry.
-
-    let cache_result = if use_cache {
-        infcx.inner.borrow_mut().projection_cache().try_start(cache_key)
-    } else {
-        Ok(())
-    };
-    match cache_result {
+    let cache_entry = infcx.inner.borrow_mut().projection_cache().try_start(cache_key);
+    match cache_entry {
         Ok(()) => debug!("no cache"),
         Err(ProjectionCacheEntry::Ambiguous) => {
             // If we found ambiguity the last time, that means we will continue
@@ -378,10 +368,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
             // Cache that normalizing this projection resulted in a cycle. This
             // should ensure that, unless this happens within a snapshot that's
             // rolled back, fulfillment or evaluation will notice the cycle.
-
-            if use_cache {
-                infcx.inner.borrow_mut().projection_cache().recur(cache_key);
-            }
+            infcx.inner.borrow_mut().projection_cache().recur(cache_key);
             return Err(InProgress);
         }
         Err(ProjectionCacheEntry::Recur) => {
@@ -445,26 +432,20 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
             let mut deduped = SsoHashSet::with_capacity(result.obligations.len());
             result.obligations.retain(|obligation| deduped.insert(obligation.clone()));
 
-            if use_cache {
-                infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
-            }
+            infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
             obligations.extend(result.obligations);
             Ok(Some(result.value))
         }
         Ok(Projected::NoProgress(projected_ty)) => {
             let result =
                 Normalized { value: projected_ty, obligations: PredicateObligations::new() };
-            if use_cache {
-                infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
-            }
+            infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
             // No need to extend `obligations`.
             Ok(Some(result.value))
         }
         Err(ProjectionError::TooManyCandidates) => {
             debug!("opt_normalize_projection_type: too many candidates");
-            if use_cache {
-                infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
-            }
+            infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
             Ok(None)
         }
         Err(ProjectionError::TraitSelectionError(_)) => {
@@ -473,10 +454,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
             // just return `ty::err` but add the obligation `T :
             // Trait`, which when processed will cause the error to be
             // reported later
-
-            if use_cache {
-                infcx.inner.borrow_mut().projection_cache().error(cache_key);
-            }
+            infcx.inner.borrow_mut().projection_cache().error(cache_key);
             let result = normalize_to_error(selcx, param_env, projection_term, cause, depth);
             obligations.extend(result.obligations);
             Ok(Some(result.value))
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index bb44645a4ce..9e1a2a3e7d2 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -87,7 +87,6 @@ impl<'tcx> InferCtxt<'tcx> {
                 Ok(result)
             })
         } else {
-            assert!(!self.intercrate);
             let c_pred =
                 self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values);
             self.tcx.at(obligation.cause.span).evaluate_obligation(c_pred)
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index e027586563e..03fde1d1598 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -16,7 +16,7 @@ use rustc_infer::traits::{
     Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError,
 };
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
-use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use tracing::{debug, instrument, trace};
 
@@ -790,7 +790,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         //
                         // Note that this is only sound as projection candidates of opaque types
                         // are always applicable for auto traits.
-                    } else if self.infcx.intercrate {
+                    } else if let TypingMode::Coherence =
+                        self.infcx.typing_mode(obligation.param_env)
+                    {
                         // We do not emit auto trait candidates for opaque types in coherence.
                         // Doing so can result in weird dependency cycles.
                         candidates.ambiguous = true;
@@ -930,7 +932,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> Option<ty::PolyExistentialTraitRef<'tcx>> {
         // Don't drop any candidates in intercrate mode, as it's incomplete.
         // (Not that it matters, since `Unsize` is not a stable trait.)
-        if self.infcx.intercrate {
+        //
+        // FIXME(@lcnr): This should probably only trigger during analysis,
+        // disabling candidates during codegen is also questionable.
+        if let TypingMode::Coherence = self.infcx.typing_mode(param_env) {
             return None;
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 635d3bc99b1..b1e5e526315 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2,6 +2,7 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection
 
+use std::assert_matches::assert_matches;
 use std::cell::{Cell, RefCell};
 use std::fmt::{self, Display};
 use std::ops::ControlFlow;
@@ -28,7 +29,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt;
 use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
 use rustc_middle::ty::{
     self, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt,
-    Upcast,
+    TypingMode, Upcast,
 };
 use rustc_span::Symbol;
 use rustc_span::symbol::sym;
@@ -222,7 +223,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// Enables tracking of intercrate ambiguity causes. See
     /// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
     pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
-        assert!(self.is_intercrate());
+        assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence);
         assert!(self.intercrate_ambiguity_causes.is_none());
         self.intercrate_ambiguity_causes = Some(FxIndexSet::default());
         debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
@@ -234,7 +235,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     pub fn take_intercrate_ambiguity_causes(
         &mut self,
     ) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> {
-        assert!(self.is_intercrate());
+        assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence);
         self.intercrate_ambiguity_causes.take().unwrap_or_default()
     }
 
@@ -242,10 +243,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         self.infcx.tcx
     }
 
-    pub fn is_intercrate(&self) -> bool {
-        self.infcx.intercrate
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // Selection
     //
@@ -1029,7 +1026,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         previous_stack: TraitObligationStackList<'o, 'tcx>,
         mut obligation: PolyTraitObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        if !self.is_intercrate()
+        if !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
             && obligation.is_global()
             && obligation.param_env.caller_bounds().iter().all(|bound| bound.has_param())
         {
@@ -1312,14 +1309,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Option<EvaluationResult> {
-        // Neither the global nor local cache is aware of intercrate
-        // mode, so don't do any caching. In particular, we might
-        // re-use the same `InferCtxt` with both an intercrate
-        // and non-intercrate `SelectionContext`
-        if self.is_intercrate() {
-            return None;
-        }
-
         let tcx = self.tcx();
         if self.can_use_global_caches(param_env) {
             if let Some(res) = tcx.evaluation_cache.get(&(param_env, trait_pred), tcx) {
@@ -1342,14 +1331,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return;
         }
 
-        // Neither the global nor local cache is aware of intercrate
-        // mode, so don't do any caching. In particular, we might
-        // re-use the same `InferCtxt` with both an intercrate
-        // and non-intercrate `SelectionContext`
-        if self.is_intercrate() {
-            return;
-        }
-
         if self.can_use_global_caches(param_env) && !trait_pred.has_infer() {
             debug!(?trait_pred, ?result, "insert_evaluation_cache global");
             // This may overwrite the cache with the same value
@@ -1476,13 +1457,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> {
-        debug!("is_knowable(intercrate={:?})", self.is_intercrate());
-
-        if !self.is_intercrate() {
-            return Ok(());
+        let obligation = &stack.obligation;
+        match self.infcx.typing_mode(obligation.param_env) {
+            TypingMode::Coherence => {}
+            TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Ok(()),
         }
 
-        let obligation = &stack.obligation;
+        debug!("is_knowable()");
+
         let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
 
         // Okay to skip binder because of the nature of the
@@ -1502,25 +1484,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return false;
         }
 
-        // Avoid using the global cache during coherence and just rely
-        // on the local cache. This effectively disables caching
-        // during coherence. It is really just a simplification to
-        // avoid us having to fear that coherence results "pollute"
-        // the master cache. Since coherence executes pretty quickly,
-        // it's not worth going to more trouble to increase the
-        // hit-rate, I don't think.
-        if self.is_intercrate() {
-            return false;
-        }
-
-        // Avoid using the global cache when we're defining opaque types
-        // as their hidden type may impact the result of candidate selection.
-        if !self.infcx.defining_opaque_types().is_empty() {
-            return false;
+        match self.infcx.typing_mode(param_env) {
+            // Avoid using the global cache during coherence and just rely
+            // on the local cache. It is really just a simplification to
+            // avoid us having to fear that coherence results "pollute"
+            // the master cache. Since coherence executes pretty quickly,
+            // it's not worth going to more trouble to increase the
+            // hit-rate, I don't think.
+            TypingMode::Coherence => false,
+            // Avoid using the global cache when we're defining opaque types
+            // as their hidden type may impact the result of candidate selection.
+            TypingMode::Analysis { defining_opaque_types } => defining_opaque_types.is_empty(),
+            // The global cache is only used if there are no opaque types in
+            // the defining scope or we're outside of analysis.
+            //
+            // FIXME(#132279): This is still incorrect as we treat opaque types
+            // and default associated items differently between these two modes.
+            TypingMode::PostAnalysis => true,
         }
-
-        // Otherwise, we can use the global cache.
-        true
     }
 
     fn check_candidate_cache(
@@ -1528,13 +1509,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
-        // Neither the global nor local cache is aware of intercrate
-        // mode, so don't do any caching. In particular, we might
-        // re-use the same `InferCtxt` with both an intercrate
-        // and non-intercrate `SelectionContext`
-        if self.is_intercrate() {
-            return None;
-        }
         let tcx = self.tcx();
         let pred = cache_fresh_trait_pred.skip_binder();
 
@@ -1566,13 +1540,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &self,
         result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>,
     ) -> bool {
-        // Neither the global nor local cache is aware of intercrate
-        // mode, so don't do any caching. In particular, we might
-        // re-use the same `InferCtxt` with both an intercrate
-        // and non-intercrate `SelectionContext`
-        if self.is_intercrate() {
-            return false;
-        }
         match result {
             Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_infer(),
             _ => true,
@@ -2541,7 +2508,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             })?;
         nested_obligations.extend(obligations);
 
-        if !self.is_intercrate() && impl_trait_header.polarity == ty::ImplPolarity::Reservation {
+        if impl_trait_header.polarity == ty::ImplPolarity::Reservation
+            && !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
+        {
             debug!("reservation impls only apply in intercrate mode");
             return Err(());
         }
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 0e45f7a195f..5bf3dbcbc32 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -19,7 +19,9 @@ use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::bug;
 use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
-use rustc_middle::ty::{self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt, TypingMode,
+};
 use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS};
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym};
 use specialization_graph::GraphExt;
@@ -184,7 +186,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
     let penv = tcx.param_env(impl1_def_id);
 
     // Create an infcx, taking the predicates of impl1 as assumptions:
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
 
     // Attempt to prove that impl2 applies, given all of the above.
     fulfill_implication(
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index ed221e2a183..bb56d6eaf54 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -9,7 +9,8 @@ use rustc_infer::traits::util::PredicateSet;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
-    self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry,
+    self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast,
+    VtblEntry,
 };
 use rustc_span::{DUMMY_SP, Span, sym};
 use smallvec::{SmallVec, smallvec};
@@ -439,7 +440,7 @@ fn trait_refs_are_compatible<'tcx>(
         return false;
     }
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
     let param_env = ty::ParamEnv::reveal_all();
     let ocx = ObligationCtxt::new(&infcx);
     let hr_source_principal =
diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs
index 11182198246..d8c1c50d79a 100644
--- a/compiler/rustc_traits/src/codegen.rs
+++ b/compiler/rustc_traits/src/codegen.rs
@@ -6,7 +6,7 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::bug;
 use rustc_middle::traits::CodegenObligationError;
-use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::{
     ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext,
@@ -30,7 +30,7 @@ pub(crate) fn codegen_select_candidate<'tcx>(
 
     // Do the initial selection for the obligation. This yields the
     // shallow result we are looking for -- that is, what specific impl.
-    let infcx = tcx.infer_ctxt().ignoring_regions().build();
+    let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::from_param_env(param_env));
     let mut selcx = SelectionContext::new(&infcx);
 
     let obligation_cause = ObligationCause::dummy();
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 3e2794f6489..d79059a39a1 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -1,7 +1,7 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt};
+use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode};
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::{Normalized, ObligationCause};
 use tracing::debug;
@@ -22,7 +22,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + Par
     goal: ParamEnvAnd<'tcx, T>,
 ) -> Result<T, NoSolution> {
     let ParamEnvAnd { param_env, value } = goal;
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
     let cause = ObligationCause::dummy();
     match infcx.at(&cause, param_env).query_normalize(value) {
         Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => {
diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs
index 51b908881eb..c26b41d8960 100644
--- a/compiler/rustc_ty_utils/src/common_traits.rs
+++ b/compiler/rustc_ty_utils/src/common_traits.rs
@@ -3,7 +3,7 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
 use rustc_trait_selection::traits;
 
 fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
@@ -29,7 +29,7 @@ fn is_item_raw<'tcx>(
 ) -> bool {
     let (param_env, ty) = query.into_parts();
     let trait_def_id = tcx.require_lang_item(item, None);
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
     traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id)
 }
 
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 9b764133f2c..e258b6dae0b 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -6,7 +6,7 @@ use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError};
 use rustc_middle::ty::util::AsyncDropGlueMorphology;
-use rustc_middle::ty::{self, GenericArgsRef, Instance, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, GenericArgsRef, Instance, TyCtxt, TypeVisitableExt, TypingMode};
 use rustc_span::sym;
 use rustc_trait_selection::traits;
 use rustc_type_ir::ClosureKind;
@@ -130,7 +130,7 @@ fn resolve_associated_item<'tcx>(
                 .unwrap_or_else(|| {
                     bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id);
                 });
-            let infcx = tcx.infer_ctxt().build();
+            let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
             let param_env = param_env.with_reveal_all_normalized(tcx);
             let args = rcvr_args.rebase_onto(tcx, trait_def_id, impl_data.args);
             let args = translate_args(
diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs
index 1ead7b731e7..0b4efab1d9c 100644
--- a/compiler/rustc_ty_utils/src/structural_match.rs
+++ b/compiler/rustc_ty_utils/src/structural_match.rs
@@ -1,7 +1,7 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
 use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
 
 /// This method returns true if and only if `adt_ty` itself has been marked as
@@ -11,7 +11,7 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
 /// Note that this does *not* recursively check if the substructure of `adt_ty`
 /// implements the trait.
 fn has_structural_eq_impl<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool {
-    let infcx = &tcx.infer_ctxt().build();
+    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let cause = ObligationCause::dummy();
 
     let ocx = ObligationCtxt::new(infcx);
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index 3fb7d87bcc4..24b2ebc1fbe 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -8,7 +8,7 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 
 use crate::inherent::*;
-use crate::{self as ty, Interner, UniverseIndex};
+use crate::{self as ty, Interner, TypingMode, UniverseIndex};
 
 #[derive_where(Clone; I: Interner, V: Clone)]
 #[derive_where(Hash; I: Interner, V: Hash)]
@@ -19,7 +19,7 @@ use crate::{self as ty, Interner, UniverseIndex};
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub struct CanonicalQueryInput<I: Interner, V> {
     pub canonical: Canonical<I, V>,
-    pub defining_opaque_types: I::DefiningOpaqueTypes,
+    pub typing_mode: TypingMode<I>,
 }
 
 /// A "canonicalized" type `V` is one where all free inference
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index 7c6a3c65ebf..22223e4a890 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -1,9 +1,68 @@
+use derive_where::derive_where;
+#[cfg(feature = "nightly")]
+use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
+
 use crate::fold::TypeFoldable;
+use crate::inherent::*;
 use crate::relate::RelateResult;
 use crate::relate::combine::PredicateEmittingRelation;
-use crate::solve::SolverMode;
+use crate::solve::Reveal;
 use crate::{self as ty, Interner};
 
+/// The current typing mode of an inference context. We unfortunately have some
+/// slightly different typing rules depending on the current context. See the
+/// doc comment for each variant for how and why they are used.
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+pub enum TypingMode<I: Interner> {
+    /// When checking whether impls overlap, we check whether any obligations
+    /// are guaranteed to never hold when unifying the impls. This requires us
+    /// to be complete: we must never fail to prove something which may actually
+    /// hold.
+    ///
+    /// In this typing mode we bail with ambiguity in case its not knowable
+    /// whether a trait goal may hold, e.g. because the trait may get implemented
+    /// in a downstream or sibling crate.
+    ///
+    /// We also have to be careful when generalizing aliases inside of higher-ranked
+    /// types to not unnecessarily constrain any inference variables.
+    Coherence,
+    /// Analysis includes type inference, checking that items are well-formed, and
+    /// pretty much everything else which may emit proper type errors to the user.
+    ///
+    /// We only normalize opaque types which may get defined by the current body,
+    /// which are stored in `defining_opaque_types`.
+    Analysis { defining_opaque_types: I::DefiningOpaqueTypes },
+    /// After analysis, mostly during codegen and MIR optimizations, we're able to
+    /// reveal all opaque types.
+    PostAnalysis,
+}
+
+impl<I: Interner> TypingMode<I> {
+    /// Analysis outside of a body does not define any opaque types.
+    pub fn non_body_analysis() -> TypingMode<I> {
+        TypingMode::Analysis { defining_opaque_types: Default::default() }
+    }
+
+    /// While typechecking a body, we need to be able to define the opaque
+    /// types defined by that body.
+    pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
+        TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
+    }
+
+    /// FIXME(#132279): Using this function is questionable as the `param_env`
+    /// does not track `defining_opaque_types` and whether we're in coherence mode.
+    /// Many uses of this function should also use a not-yet implemented typing mode
+    /// which reveals already defined opaque types in the future. This function will
+    /// get completely removed at some point.
+    pub fn from_param_env(param_env: I::ParamEnv) -> TypingMode<I> {
+        match param_env.reveal() {
+            Reveal::UserFacing => TypingMode::non_body_analysis(),
+            Reveal::All => TypingMode::PostAnalysis,
+        }
+    }
+}
+
 pub trait InferCtxtLike: Sized {
     type Interner: Interner;
     fn cx(&self) -> Self::Interner;
@@ -16,7 +75,10 @@ pub trait InferCtxtLike: Sized {
         true
     }
 
-    fn solver_mode(&self) -> SolverMode;
+    fn typing_mode(
+        &self,
+        param_env_for_debug_assertion: <Self::Interner as Interner>::ParamEnv,
+    ) -> TypingMode<Self::Interner>;
 
     fn universe(&self) -> ty::UniverseIndex;
     fn create_next_universe(&self) -> ty::UniverseIndex;
@@ -43,8 +105,6 @@ pub trait InferCtxtLike: Sized {
         vid: ty::RegionVid,
     ) -> <Self::Interner as Interner>::Region;
 
-    fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
-
     fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
     fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
     fn fresh_args_for_item(
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 6a8113b38b7..36ddddccfa2 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -11,9 +11,7 @@ use crate::inherent::*;
 use crate::ir_print::IrPrint;
 use crate::lang_items::TraitSolverLangItem;
 use crate::relate::Relate;
-use crate::solve::{
-    CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode,
-};
+use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult};
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
 use crate::{self as ty, search_graph};
 
@@ -130,11 +128,7 @@ pub trait Interner:
     type Clause: Clause<Self>;
     type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
 
-    fn with_global_cache<R>(
-        self,
-        mode: SolverMode,
-        f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
-    ) -> R;
+    fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R;
 
     fn evaluation_is_concurrent(&self) -> bool;
 
@@ -298,6 +292,11 @@ pub trait Interner:
         self,
         binder: ty::Binder<Self, T>,
     ) -> ty::Binder<Self, T>;
+
+    fn opaque_types_defined_by(
+        self,
+        defining_anchor: Self::LocalDefId,
+    ) -> Self::DefiningOpaqueTypes;
 }
 
 /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
@@ -414,12 +413,8 @@ impl<I: Interner> search_graph::Cx for I {
     fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, I::DepNodeIndex) {
         I::with_cached_task(self, task)
     }
-    fn with_global_cache<R>(
-        self,
-        mode: SolverMode,
-        f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
-    ) -> R {
-        I::with_global_cache(self, mode, f)
+    fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R {
+        I::with_global_cache(self, f)
     }
     fn evaluation_is_concurrent(&self) -> bool {
         self.evaluation_is_concurrent()
diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs
index 17a3912730f..53751f7711a 100644
--- a/compiler/rustc_type_ir/src/relate/combine.rs
+++ b/compiler/rustc_type_ir/src/relate/combine.rs
@@ -6,9 +6,9 @@ use super::{
 };
 use crate::error::TypeError;
 use crate::inherent::*;
-use crate::solve::{Goal, SolverMode};
+use crate::solve::Goal;
 use crate::visit::TypeVisitableExt as _;
-use crate::{self as ty, InferCtxtLike, Interner, Upcast};
+use crate::{self as ty, InferCtxtLike, Interner, TypingMode, Upcast};
 
 pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>:
     TypeRelation<I>
@@ -128,19 +128,19 @@ where
         }
 
         (ty::Alias(ty::Opaque, _), _) | (_, ty::Alias(ty::Opaque, _)) => {
-            match infcx.solver_mode() {
-                SolverMode::Normal => {
-                    assert!(!infcx.next_trait_solver());
-                    structurally_relate_tys(relation, a, b)
-                }
+            assert!(!infcx.next_trait_solver());
+            match infcx.typing_mode(relation.param_env()) {
                 // During coherence, opaque types should be treated as *possibly*
-                // equal to any other type (except for possibly itinfcx). This is an
+                // equal to any other type. This is an
                 // extremely heavy hammer, but can be relaxed in a forwards-compatible
                 // way later.
-                SolverMode::Coherence => {
+                TypingMode::Coherence => {
                     relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
                     Ok(a)
                 }
+                TypingMode::Analysis { .. } | TypingMode::PostAnalysis => {
+                    structurally_relate_tys(relation, a, b)
+                }
             }
         }
 
diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs
index 3fd2bb61ba5..5010fc09adc 100644
--- a/compiler/rustc_type_ir/src/search_graph/mod.rs
+++ b/compiler/rustc_type_ir/src/search_graph/mod.rs
@@ -22,7 +22,6 @@ use rustc_index::{Idx, IndexVec};
 use tracing::debug;
 
 use crate::data_structures::HashMap;
-use crate::solve::SolverMode;
 
 mod global_cache;
 use global_cache::CacheData;
@@ -48,11 +47,7 @@ pub trait Cx: Copy {
     fn get_tracked<T: Debug + Clone>(self, tracked: &Self::Tracked<T>) -> T;
     fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex);
 
-    fn with_global_cache<R>(
-        self,
-        mode: SolverMode,
-        f: impl FnOnce(&mut GlobalCache<Self>) -> R,
-    ) -> R;
+    fn with_global_cache<R>(self, f: impl FnOnce(&mut GlobalCache<Self>) -> R) -> R;
 
     fn evaluation_is_concurrent(&self) -> bool;
 }
@@ -358,7 +353,6 @@ struct ProvisionalCacheEntry<X: Cx> {
 }
 
 pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
-    mode: SolverMode,
     root_depth: AvailableDepth,
     /// The stack of goals currently being computed.
     ///
@@ -374,9 +368,8 @@ pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
 }
 
 impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
-    pub fn new(mode: SolverMode, root_depth: usize) -> SearchGraph<D> {
+    pub fn new(root_depth: usize) -> SearchGraph<D> {
         Self {
-            mode,
             root_depth: AvailableDepth(root_depth),
             stack: Default::default(),
             provisional_cache: Default::default(),
@@ -384,10 +377,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         }
     }
 
-    pub fn solver_mode(&self) -> SolverMode {
-        self.mode
-    }
-
     /// Lazily update the stack entry for the parent goal.
     /// This behavior is shared between actually evaluating goals
     /// and using existing global cache entries to make sure they
@@ -829,7 +818,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         input: X::Input,
         available_depth: AvailableDepth,
     ) -> Option<X::Result> {
-        cx.with_global_cache(self.mode, |cache| {
+        cx.with_global_cache(|cache| {
             cache
                 .get(cx, input, available_depth, |nested_goals| {
                     Self::candidate_is_applicable(
@@ -852,7 +841,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         input: X::Input,
         available_depth: AvailableDepth,
     ) -> Option<X::Result> {
-        cx.with_global_cache(self.mode, |cache| {
+        cx.with_global_cache(|cache| {
             let CacheData { result, additional_depth, encountered_overflow, nested_goals } = cache
                 .get(cx, input, available_depth, |nested_goals| {
                     Self::candidate_is_applicable(
@@ -1041,7 +1030,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
     ) {
         let additional_depth = final_entry.reached_depth.as_usize() - self.stack.len();
         debug!(?final_entry, ?result, "insert global cache");
-        cx.with_global_cache(self.mode, |cache| {
+        cx.with_global_cache(|cache| {
             cache.insert(
                 cx,
                 input,
diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs
index b3f8390bbf0..fe455873051 100644
--- a/compiler/rustc_type_ir/src/solve/mod.rs
+++ b/compiler/rustc_type_ir/src/solve/mod.rs
@@ -58,19 +58,6 @@ pub enum Reveal {
     All,
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum SolverMode {
-    /// Ordinary trait solving, using everywhere except for coherence.
-    Normal,
-    /// Trait solving during coherence. There are a few notable differences
-    /// between coherence and ordinary trait solving.
-    ///
-    /// Most importantly, trait solving during coherence must not be incomplete,
-    /// i.e. return `Err(NoSolution)` for goals for which a solution exists.
-    /// This means that we must not make any guesses or arbitrary choices.
-    Coherence,
-}
-
 pub type CanonicalInput<I, T = <I as Interner>::Predicate> =
     ty::CanonicalQueryInput<I, QueryInput<I, T>>;
 pub type CanonicalResponse<I> = Canonical<I, Response<I>>;
diff --git a/src/doc/rustc/src/platform-support/aix.md b/src/doc/rustc/src/platform-support/aix.md
index c3ce71a1835..5a198062b95 100644
--- a/src/doc/rustc/src/platform-support/aix.md
+++ b/src/doc/rustc/src/platform-support/aix.md
@@ -6,8 +6,8 @@ Rust for AIX operating system, currently only 64-bit PowerPC is supported.
 
 ## Target maintainers
 
-- QIU Chaofan `qiucofan@cn.ibm.com`, https://github.com/ecnelises
-- Kai LUO, `lkail@cn.ibm.com`, https://github.com/bzEq
+- David Tenty `daltenty@ibm.com`, https://github.com/daltenty
+- Chris Cambly, `ccambly@ca.ibm.com`, https://github.com/gilamn5tr
 
 ## Requirements
 
diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md
index 0622f4dd564..489f46e1cb9 100644
--- a/src/doc/rustc/src/platform-support/fuchsia.md
+++ b/src/doc/rustc/src/platform-support/fuchsia.md
@@ -7,17 +7,9 @@ updatable, and performant.
 
 ## Target maintainers
 
-The [Fuchsia team]:
+See [`fuchsia.toml`] in the `team` repository for current target maintainers.
 
-- Tyler Mandry ([@tmandry](https://github.com/tmandry))
-- David Koloski ([@djkoloski](https://github.com/djkoloski))
-- Julia Ryan ([@P1n3appl3](https://github.com/P1n3appl3))
-- Erick Tryzelaar ([@erickt](https://github.com/erickt))
-
-As the team evolves over time, the specific members listed here may differ from
-the members reported by the API. The API should be considered to be
-authoritative if this occurs. Instead of pinging individual members, use
-`@rustbot ping fuchsia` to contact the team on GitHub.
+[`fuchsia.toml`]: https://github.com/rust-lang/team/blob/master/teams/fuchsia.toml
 
 ## Table of contents
 
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 1f3cb4a61b8..a6d9676dd84 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -1,7 +1,7 @@
 use rustc_hir as hir;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
 use rustc_infer::traits;
-use rustc_middle::ty::{self, Upcast};
+use rustc_middle::ty::{self, TypingMode, Upcast};
 use rustc_span::DUMMY_SP;
 use rustc_span::def_id::DefId;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -38,7 +38,7 @@ pub(crate) fn synthesize_blanket_impls(
             if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
                 continue;
             }
-            let infcx = tcx.infer_ctxt().build();
+            let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
             let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id);
             let impl_ty = ty.instantiate(tcx, args);
             let param_env = ty::ParamEnv::empty();
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ea349f878e0..87b629078ff 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -45,7 +45,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId};
 use rustc_hir_analysis::lower_ty;
 use rustc_middle::metadata::Reexport;
 use rustc_middle::middle::resolve_bound_vars as rbv;
-use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use rustc_span::ExpnKind;
 use rustc_span::hygiene::{AstPass, MacroKind};
@@ -1863,7 +1863,7 @@ fn normalize<'tcx>(
     use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 
     // Try to normalize `<X as Y>::T` to a type
-    let infcx = cx.tcx.infer_ctxt().build();
+    let infcx = cx.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let normalized = infcx
         .at(&ObligationCause::dummy(), cx.param_env)
         .query_normalize(ty)
@@ -2399,7 +2399,7 @@ pub(crate) fn clean_variant_def_with_args<'tcx>(
     use rustc_trait_selection::infer::TyCtxtInferExt;
     use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 
-    let infcx = cx.tcx.infer_ctxt().build();
+    let infcx = cx.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let kind = match variant.ctor_kind() {
         Some(CtorKind::Const) => VariantKind::CLike,
         Some(CtorKind::Fn) => VariantKind::Tuple(
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 8e8e5c6ade8..47c21d89177 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -20,8 +20,7 @@ use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_metadata::creader::{CStore, LoadedMacro};
-use rustc_middle::ty;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_span::symbol::kw;
 use rustc_span::{Symbol, sym};
 use rustc_target::spec::abi::Abi;
@@ -613,7 +612,7 @@ fn generate_item_def_id_path(
     // No need to try to infer the actual parent item if it's not an associated item from the `impl`
     // block.
     if def_id != original_def_id && matches!(tcx.def_kind(def_id), DefKind::Impl { .. }) {
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         def_id = infcx
             .at(&ObligationCause::dummy(), tcx.param_env(def_id))
             .query_normalize(ty::Binder::dummy(tcx.type_of(def_id).instantiate_identity()))
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index cabc6592258..6ca599ed361 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -9,7 +9,8 @@ use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Saf
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
-    self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt, TypeckResults,
+    self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt,
+    TypeckResults,
 };
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
@@ -203,7 +204,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc
                             // 'cuz currently nothing changes after deleting this check.
                             local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
                         }) {
-                            match cx.tcx.infer_ctxt().build().err_ctxt().type_implements_fn_trait(
+                            match cx.tcx.infer_ctxt().build(cx.typing_mode()).err_ctxt().type_implements_fn_trait(
                                 cx.param_env,
                                 Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
                                 ty::PredicatePolarity::Positive,
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index cfd11e9339f..c74ba088b78 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -117,7 +117,7 @@ fn check_needless_must_use(
     } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
         // Ignore async functions unless Future::Output type is a must_use type
         if sig.header.is_async() {
-            let infcx = cx.tcx.infer_ctxt().build();
+            let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
             if let Some(future_ty) = infcx.err_ctxt().get_impl_future_output_ty(return_ty(cx, item_id))
                 && !is_must_use_ty(cx, future_ty)
             {
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index a4dbe134f36..cf08c16458b 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
             if is_future {
                 let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
                 let span = decl.output.span();
-                let infcx = cx.tcx.infer_ctxt().build();
+                let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
                 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
                 let cause = traits::ObligationCause::misc(span, fn_def_id);
                 ocx.register_bound(cause, cx.param_env, ret_ty, send_trait);
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index cfa1fdb8137..82549413fa9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -568,7 +568,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                             let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
                             !cx.tcx
                                 .infer_ctxt()
-                                .build()
+                                .build(cx.typing_mode())
                                 .predicate_must_hold_modulo_regions(&obligation)
                         }) {
                             return false;
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index f6db12ed84e..f7fa31d83aa 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -278,7 +278,7 @@ fn needless_borrow_count<'tcx>(
 
             let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, &args_with_referent_ty[..]);
             let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
-            let infcx = cx.tcx.infer_ctxt().build();
+            let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
             infcx.predicate_must_hold_modulo_regions(&obligation)
         })
     };
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 392cfcb813e..2e5195d459f 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -160,7 +160,7 @@ impl NoEffect {
                                 // Remove `impl Future<Output = T>` to get `T`
                                 if cx.tcx.ty_is_opaque_future(ret_ty)
                                     && let Some(true_ret_ty) =
-                                        cx.tcx.infer_ctxt().build().err_ctxt().get_impl_future_output_ty(ret_ty)
+                                        cx.tcx.infer_ctxt().build(cx.typing_mode()).err_ctxt().get_impl_future_output_ty(ret_ty)
                                 {
                                     ret_ty = true_ret_ty;
                                 }
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index f5fcf521b96..a548c6ef3b1 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -695,7 +695,7 @@ fn matches_preds<'tcx>(
     ty: Ty<'tcx>,
     preds: &'tcx [ty::PolyExistentialPredicate<'tcx>],
 ) -> bool {
-    let infcx = cx.tcx.infer_ctxt().build();
+    let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
     preds
         .iter()
         .all(|&p| match cx.tcx.instantiate_bound_regions_with_erased(p) {
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index ec3a693d2ef..3b05abc546f 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -114,7 +114,7 @@ fn into_iter_bound<'tcx>(
                     if !cx
                         .tcx
                         .infer_ctxt()
-                        .build()
+                        .build(cx.typing_mode())
                         .predicate_must_hold_modulo_regions(&obligation)
                     {
                         return None;
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index a00196c4b51..6b3078f52af 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -185,9 +185,7 @@ impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
             vis.into_map(cx)
         };
         let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
-            .into_engine(cx.tcx, mir)
-            .pass_name("redundant_clone")
-            .iterate_to_fixpoint()
+            .iterate_to_fixpoint(cx.tcx, mir, Some("redundant_clone"))
             .into_results_cursor(mir);
         let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
         vis.visit_body(mir);
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 46739862de6..dbadc8432f6 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -17,7 +17,7 @@ use rustc_middle::mir::{
 };
 use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause};
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt, TypingMode};
 use rustc_span::Span;
 use rustc_span::symbol::sym;
 use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext};
@@ -420,7 +420,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
             TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]),
         );
 
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(obligation.param_env));
         let mut selcx = SelectionContext::new(&infcx);
         let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
             return false;
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 07c3d0eada0..c618bfe4488 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -19,7 +19,7 @@ use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
     self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind,
     GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
+    TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, TypingMode,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
@@ -268,7 +268,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
         return false;
     }
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
     let args = args
         .into_iter()
         .map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into()))
@@ -362,7 +362,7 @@ fn is_normalizable_helper<'tcx>(
     }
     // prevent recursive loops, false-negative is better than endless loop leading to stack overflow
     cache.insert(ty, false);
-    let infcx = cx.tcx.infer_ctxt().build();
+    let infcx = cx.tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
     let cause = ObligationCause::dummy();
     let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() {
         match ty.kind() {
@@ -1268,7 +1268,7 @@ pub fn make_normalized_projection_with_regions<'tcx>(
         let cause = ObligationCause::dummy();
         match tcx
             .infer_ctxt()
-            .build()
+            .build(TypingMode::from_param_env(param_env))
             .at(&cause, param_env)
             .query_normalize(Ty::new_projection_from_args(tcx, ty.def_id, ty.args))
         {
@@ -1284,7 +1284,7 @@ pub fn make_normalized_projection_with_regions<'tcx>(
 
 pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
     let cause = ObligationCause::dummy();
-    match tcx.infer_ctxt().build().at(&cause, param_env).query_normalize(ty) {
+    match tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)).at(&cause, param_env).query_normalize(ty) {
         Ok(ty) => ty.value,
         Err(_) => ty,
     }
diff --git a/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs b/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs
index 574a53c58fe..0f99f6b1b1e 100644
--- a/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs
+++ b/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs
@@ -1,3 +1,3 @@
 pub fn main() {
-    vec![,]; //~ ERROR no rules expected the token `,`
+    vec![,]; //~ ERROR no rules expected `,`
 }
diff --git a/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr b/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr
index b3f953af6d2..d76d493eca8 100644
--- a/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr
+++ b/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `,`
+error: no rules expected `,`
   --> $DIR/vec-macro-with-comma-only.rs:2:10
    |
 LL |     vec![,];
diff --git a/tests/ui/editions/edition-keywords-2015-2015-parsing.rs b/tests/ui/editions/edition-keywords-2015-2015-parsing.rs
index 07104bdf217..4751d280467 100644
--- a/tests/ui/editions/edition-keywords-2015-2015-parsing.rs
+++ b/tests/ui/editions/edition-keywords-2015-2015-parsing.rs
@@ -13,8 +13,8 @@ pub fn check_async() {
     let mut r#async = 1; // OK
 
     r#async = consumes_async!(async); // OK
-    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
-    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected `async`
     r#async = consumes_async_raw!(r#async); // OK
 
     if passes_ident!(async) == 1 {} // OK
diff --git a/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr
index 39944622d07..2519a9fded2 100644
--- a/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `r#async`
+error: no rules expected `r#async`
   --> $DIR/edition-keywords-2015-2015-parsing.rs:16:31
    |
 LL |     r#async = consumes_async!(r#async);
@@ -10,7 +10,7 @@ note: while trying to match `async`
 LL |     (async) => (1)
    |      ^^^^^
 
-error: no rules expected the token `async`
+error: no rules expected `async`
   --> $DIR/edition-keywords-2015-2015-parsing.rs:17:35
    |
 LL |     r#async = consumes_async_raw!(async);
diff --git a/tests/ui/editions/edition-keywords-2015-2018-parsing.rs b/tests/ui/editions/edition-keywords-2015-2018-parsing.rs
index 3c294f95cd2..4404ea26fb3 100644
--- a/tests/ui/editions/edition-keywords-2015-2018-parsing.rs
+++ b/tests/ui/editions/edition-keywords-2015-2018-parsing.rs
@@ -13,8 +13,8 @@ pub fn check_async() {
     let mut r#async = 1; // OK
 
     r#async = consumes_async!(async); // OK
-    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
-    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected `async`
     r#async = consumes_async_raw!(r#async); // OK
 
     if passes_ident!(async) == 1 {} // OK
diff --git a/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr
index fa83908e666..0c0e5738415 100644
--- a/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `r#async`
+error: no rules expected `r#async`
   --> $DIR/edition-keywords-2015-2018-parsing.rs:16:31
    |
 LL |     r#async = consumes_async!(r#async);
@@ -10,7 +10,7 @@ note: while trying to match `async`
 LL |     (async) => (1)
    |      ^^^^^
 
-error: no rules expected the token `async`
+error: no rules expected `async`
   --> $DIR/edition-keywords-2015-2018-parsing.rs:17:35
    |
 LL |     r#async = consumes_async_raw!(async);
diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs
index 59184543274..c346be50856 100644
--- a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs
+++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs
@@ -17,8 +17,8 @@ pub fn check_async() {
     let mut r#async = 1; // OK
 
     r#async = consumes_async!(async); // OK
-    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
-    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected keyword `async`
     r#async = consumes_async_raw!(r#async); // OK
 
     if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
index 42db75f6659..aed5837abea 100644
--- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
@@ -20,19 +20,19 @@ help: escape `async` to use it as an identifier
 LL |     module::r#async();
    |             ++
 
-error: no rules expected the token `r#async`
+error: no rules expected `r#async`
   --> $DIR/edition-keywords-2018-2015-parsing.rs:20:31
    |
 LL |     r#async = consumes_async!(r#async);
    |                               ^^^^^^^ no rules expected this token in macro call
    |
-note: while trying to match `async`
+note: while trying to match keyword `async`
   --> $DIR/auxiliary/edition-kw-macro-2015.rs:17:6
    |
 LL |     (async) => (1)
    |      ^^^^^
 
-error: no rules expected the token `async`
+error: no rules expected keyword `async`
   --> $DIR/edition-keywords-2018-2015-parsing.rs:21:35
    |
 LL |     r#async = consumes_async_raw!(async);
diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs
index 4975246fa94..b75b68b3feb 100644
--- a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs
+++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs
@@ -24,8 +24,8 @@ pub fn check_async() {
     let mut r#async = 1; // OK
 
     r#async = consumes_async!(async); // OK
-    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
-    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected keyword `async`
     r#async = consumes_async_raw!(r#async); // OK
 
     if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
index 4bbe1597233..6503e9cc73c 100644
--- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
@@ -20,19 +20,19 @@ help: escape `async` to use it as an identifier
 LL |     module::r#async();
    |             ++
 
-error: no rules expected the token `r#async`
+error: no rules expected `r#async`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:27:31
    |
 LL |     r#async = consumes_async!(r#async);
    |                               ^^^^^^^ no rules expected this token in macro call
    |
-note: while trying to match `async`
+note: while trying to match keyword `async`
   --> $DIR/auxiliary/edition-kw-macro-2018.rs:17:6
    |
 LL |     (async) => (1)
    |      ^^^^^
 
-error: no rules expected the token `async`
+error: no rules expected keyword `async`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:28:35
    |
 LL |     r#async = consumes_async_raw!(async);
diff --git a/tests/ui/fail-simple.rs b/tests/ui/fail-simple.rs
index cd81a5d0a0f..55e547ee72b 100644
--- a/tests/ui/fail-simple.rs
+++ b/tests/ui/fail-simple.rs
@@ -1,3 +1,3 @@
 fn main() {
-    panic!(@); //~ ERROR no rules expected the token `@`
+    panic!(@); //~ ERROR no rules expected `@`
 }
diff --git a/tests/ui/fail-simple.stderr b/tests/ui/fail-simple.stderr
index 39fec3e2517..50c350b3ef5 100644
--- a/tests/ui/fail-simple.stderr
+++ b/tests/ui/fail-simple.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `@`
+error: no rules expected `@`
   --> $DIR/fail-simple.rs:2:12
    |
 LL |     panic!(@);
diff --git a/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr
index 1e73320e439..7582c8e8659 100644
--- a/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr
+++ b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr
@@ -10,7 +10,7 @@ error: expected one of `,`, `.`, `?`, or an operator, found `some`
 LL |     assert!(true some extra junk);
    |                  ^^^^ expected one of `,`, `.`, `?`, or an operator
 
-error: no rules expected the token `blah`
+error: no rules expected `blah`
   --> $DIR/assert-trailing-junk.rs:15:30
    |
 LL |     assert!(true, "whatever" blah);
@@ -28,7 +28,7 @@ LL |     assert!(true "whatever" blah);
    |                 |
    |                 help: try adding a comma
 
-error: no rules expected the token `blah`
+error: no rules expected `blah`
   --> $DIR/assert-trailing-junk.rs:18:29
    |
 LL |     assert!(true "whatever" blah);
diff --git a/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr
index 1e73320e439..7582c8e8659 100644
--- a/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr
+++ b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr
@@ -10,7 +10,7 @@ error: expected one of `,`, `.`, `?`, or an operator, found `some`
 LL |     assert!(true some extra junk);
    |                  ^^^^ expected one of `,`, `.`, `?`, or an operator
 
-error: no rules expected the token `blah`
+error: no rules expected `blah`
   --> $DIR/assert-trailing-junk.rs:15:30
    |
 LL |     assert!(true, "whatever" blah);
@@ -28,7 +28,7 @@ LL |     assert!(true "whatever" blah);
    |                 |
    |                 help: try adding a comma
 
-error: no rules expected the token `blah`
+error: no rules expected `blah`
   --> $DIR/assert-trailing-junk.rs:18:29
    |
 LL |     assert!(true "whatever" blah);
diff --git a/tests/ui/macros/best-failure.rs b/tests/ui/macros/best-failure.rs
index bbdd465d5ec..1b73066c874 100644
--- a/tests/ui/macros/best-failure.rs
+++ b/tests/ui/macros/best-failure.rs
@@ -2,7 +2,7 @@ macro_rules! number {
     (neg false, $self:ident) => { $self };
     ($signed:tt => $ty:ty;) => {
         number!(neg $signed, $self);
-        //~^ ERROR no rules expected the token `$`
+        //~^ ERROR no rules expected `$`
     };
 }
 
diff --git a/tests/ui/macros/best-failure.stderr b/tests/ui/macros/best-failure.stderr
index c5f8b9abc19..914ff7fd820 100644
--- a/tests/ui/macros/best-failure.stderr
+++ b/tests/ui/macros/best-failure.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `$`
+error: no rules expected `$`
   --> $DIR/best-failure.rs:4:30
    |
 LL | macro_rules! number {
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
index 22d662aaaf2..bf7eb3888b3 100644
--- a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
+++ b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `const`
+error: no rules expected keyword `const`
   --> $DIR/expr_2021_inline_const.rs:23:12
    |
 LL | macro_rules! m2021 {
@@ -13,7 +13,7 @@ note: while trying to match meta-variable `$e:expr_2021`
 LL |     ($e:expr_2021) => {
    |      ^^^^^^^^^^^^
 
-error: no rules expected the token `const`
+error: no rules expected keyword `const`
   --> $DIR/expr_2021_inline_const.rs:24:12
    |
 LL | macro_rules! m2024 {
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
index 2555e4f757a..1028ddc4267 100644
--- a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
+++ b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `const`
+error: no rules expected keyword `const`
   --> $DIR/expr_2021_inline_const.rs:23:12
    |
 LL | macro_rules! m2021 {
diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs
index 39a542fe4d9..312256f1879 100644
--- a/tests/ui/macros/expr_2021_inline_const.rs
+++ b/tests/ui/macros/expr_2021_inline_const.rs
@@ -20,8 +20,8 @@ macro_rules! test {
 }
 
 fn main() {
-    m2021!(const { 1 }); //~ ERROR: no rules expected the token `const`
-    m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected the token `const`
+    m2021!(const { 1 }); //~ ERROR: no rules expected keyword `const`
+    m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected keyword `const`
 
     test!(expr);
 }
diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr
index 34df20a69ef..7b3ca54bb71 100644
--- a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr
+++ b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `_`
+error: no rules expected reserved identifier `_`
   --> $DIR/expr_2024_underscore_expr.rs:19:12
    |
 LL | macro_rules! m2021 {
@@ -13,7 +13,7 @@ note: while trying to match meta-variable `$e:expr_2021`
 LL |     ($e:expr_2021) => {
    |      ^^^^^^^^^^^^
 
-error: no rules expected the token `_`
+error: no rules expected reserved identifier `_`
   --> $DIR/expr_2024_underscore_expr.rs:20:12
    |
 LL | macro_rules! m2024 {
diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr
index 372c5d8637c..59104dafa18 100644
--- a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr
+++ b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `_`
+error: no rules expected reserved identifier `_`
   --> $DIR/expr_2024_underscore_expr.rs:19:12
    |
 LL | macro_rules! m2021 {
diff --git a/tests/ui/macros/expr_2024_underscore_expr.rs b/tests/ui/macros/expr_2024_underscore_expr.rs
index 86e31374506..6f8ec139109 100644
--- a/tests/ui/macros/expr_2024_underscore_expr.rs
+++ b/tests/ui/macros/expr_2024_underscore_expr.rs
@@ -16,6 +16,6 @@ macro_rules! m2024 {
 }
 
 fn main() {
-    m2021!(_); //~ ERROR: no rules expected the token `_`
-    m2024!(_); //[edi2021]~ ERROR: no rules expected the token `_`
+    m2021!(_); //~ ERROR: no rules expected reserved identifier `_`
+    m2024!(_); //[edi2021]~ ERROR: no rules expected reserved identifier `_`
 }
diff --git a/tests/ui/macros/issue-118786.rs b/tests/ui/macros/issue-118786.rs
index a41372e4ea8..a73b737fe07 100644
--- a/tests/ui/macros/issue-118786.rs
+++ b/tests/ui/macros/issue-118786.rs
@@ -5,7 +5,7 @@
 macro_rules! make_macro {
     ($macro_name:tt) => {
         macro_rules! $macro_name {
-        //~^ ERROR macro expansion ignores token `{` and any following
+        //~^ ERROR macro expansion ignores `{` and any tokens following
         //~| ERROR cannot find macro `macro_rules` in this scope
         //~| put a macro name here
             () => {}
diff --git a/tests/ui/macros/issue-118786.stderr b/tests/ui/macros/issue-118786.stderr
index 256b742ee16..7fa5c2b83dd 100644
--- a/tests/ui/macros/issue-118786.stderr
+++ b/tests/ui/macros/issue-118786.stderr
@@ -13,7 +13,7 @@ help: add a semicolon
 LL |         macro_rules! $macro_name; {
    |                                 +
 
-error: macro expansion ignores token `{` and any following
+error: macro expansion ignores `{` and any tokens following
   --> $DIR/issue-118786.rs:7:34
    |
 LL |         macro_rules! $macro_name {
diff --git a/tests/ui/macros/issue-30007.rs b/tests/ui/macros/issue-30007.rs
index 918a821bae9..e36e47a3e7c 100644
--- a/tests/ui/macros/issue-30007.rs
+++ b/tests/ui/macros/issue-30007.rs
@@ -1,5 +1,5 @@
 macro_rules! t {
-    () => ( String ; );     //~ ERROR macro expansion ignores token `;`
+    () => ( String ; );     //~ ERROR macro expansion ignores `;`
 }
 
 fn main() {
diff --git a/tests/ui/macros/issue-30007.stderr b/tests/ui/macros/issue-30007.stderr
index f303221cf8a..129733ed69a 100644
--- a/tests/ui/macros/issue-30007.stderr
+++ b/tests/ui/macros/issue-30007.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `;` and any following
+error: macro expansion ignores `;` and any tokens following
   --> $DIR/issue-30007.rs:2:20
    |
 LL |     () => ( String ; );
diff --git a/tests/ui/macros/issue-54441.rs b/tests/ui/macros/issue-54441.rs
index b24d7e1f6be..37ab4e63647 100644
--- a/tests/ui/macros/issue-54441.rs
+++ b/tests/ui/macros/issue-54441.rs
@@ -1,6 +1,6 @@
 macro_rules! m {
     () => {
-        let //~ ERROR macro expansion ignores token `let` and any following
+        let //~ ERROR macro expansion ignores keyword `let` and any tokens following
     };
 }
 
diff --git a/tests/ui/macros/issue-54441.stderr b/tests/ui/macros/issue-54441.stderr
index fb2c103139b..f5f8b8ca2b2 100644
--- a/tests/ui/macros/issue-54441.stderr
+++ b/tests/ui/macros/issue-54441.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `let` and any following
+error: macro expansion ignores keyword `let` and any tokens following
   --> $DIR/issue-54441.rs:3:9
    |
 LL |         let
diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.rs b/tests/ui/macros/macro-at-most-once-rep-2015.rs
index 8f2531a25ae..08967b82531 100644
--- a/tests/ui/macros/macro-at-most-once-rep-2015.rs
+++ b/tests/ui/macros/macro-at-most-once-rep-2015.rs
@@ -22,21 +22,21 @@ macro_rules! barstar {
 pub fn main() {
     foo!();
     foo!(a);
-    foo!(a?); //~ ERROR no rules expected the token `?`
-    foo!(a?a); //~ ERROR no rules expected the token `?`
-    foo!(a?a?a); //~ ERROR no rules expected the token `?`
+    foo!(a?); //~ ERROR no rules expected `?`
+    foo!(a?a); //~ ERROR no rules expected `?`
+    foo!(a?a?a); //~ ERROR no rules expected `?`
 
     barplus!(); //~ERROR unexpected end of macro invocation
     barplus!(a); //~ERROR unexpected end of macro invocation
-    barplus!(a?); //~ ERROR no rules expected the token `?`
-    barplus!(a?a); //~ ERROR no rules expected the token `?`
+    barplus!(a?); //~ ERROR no rules expected `?`
+    barplus!(a?a); //~ ERROR no rules expected `?`
     barplus!(a+);
     barplus!(+);
 
     barstar!(); //~ERROR unexpected end of macro invocation
     barstar!(a); //~ERROR unexpected end of macro invocation
-    barstar!(a?); //~ ERROR no rules expected the token `?`
-    barstar!(a?a); //~ ERROR no rules expected the token `?`
+    barstar!(a?); //~ ERROR no rules expected `?`
+    barstar!(a?a); //~ ERROR no rules expected `?`
     barstar!(a*);
     barstar!(*);
 }
diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.stderr b/tests/ui/macros/macro-at-most-once-rep-2015.stderr
index 7c45b85bc8d..7f161cdc8d0 100644
--- a/tests/ui/macros/macro-at-most-once-rep-2015.stderr
+++ b/tests/ui/macros/macro-at-most-once-rep-2015.stderr
@@ -4,7 +4,7 @@ error: the `?` macro repetition operator does not take a separator
 LL |     ($(a),?) => {};
    |          ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:25:11
    |
 LL | macro_rules! foo {
@@ -15,7 +15,7 @@ LL |     foo!(a?);
    |
    = note: while trying to match sequence end
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:26:11
    |
 LL | macro_rules! foo {
@@ -26,7 +26,7 @@ LL |     foo!(a?a);
    |
    = note: while trying to match sequence end
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:27:11
    |
 LL | macro_rules! foo {
@@ -67,7 +67,7 @@ note: while trying to match `+`
 LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:31:15
    |
 LL | macro_rules! barplus {
@@ -82,7 +82,7 @@ note: while trying to match `+`
 LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:32:15
    |
 LL | macro_rules! barplus {
@@ -127,7 +127,7 @@ note: while trying to match `*`
 LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:38:15
    |
 LL | macro_rules! barstar {
@@ -142,7 +142,7 @@ note: while trying to match `*`
 LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:39:15
    |
 LL | macro_rules! barstar {
diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.rs b/tests/ui/macros/macro-at-most-once-rep-2018.rs
index 7f43055ded6..98fbb2ad207 100644
--- a/tests/ui/macros/macro-at-most-once-rep-2018.rs
+++ b/tests/ui/macros/macro-at-most-once-rep-2018.rs
@@ -22,21 +22,21 @@ macro_rules! barstar {
 pub fn main() {
     foo!();
     foo!(a);
-    foo!(a?); //~ ERROR no rules expected the token `?`
-    foo!(a?a); //~ ERROR no rules expected the token `?`
-    foo!(a?a?a); //~ ERROR no rules expected the token `?`
+    foo!(a?); //~ ERROR no rules expected `?`
+    foo!(a?a); //~ ERROR no rules expected `?`
+    foo!(a?a?a); //~ ERROR no rules expected `?`
 
     barplus!(); //~ERROR unexpected end of macro invocation
     barplus!(a); //~ERROR unexpected end of macro invocation
-    barplus!(a?); //~ ERROR no rules expected the token `?`
-    barplus!(a?a); //~ ERROR no rules expected the token `?`
+    barplus!(a?); //~ ERROR no rules expected `?`
+    barplus!(a?a); //~ ERROR no rules expected `?`
     barplus!(a+);
     barplus!(+);
 
     barstar!(); //~ERROR unexpected end of macro invocation
     barstar!(a); //~ERROR unexpected end of macro invocation
-    barstar!(a?); //~ ERROR no rules expected the token `?`
-    barstar!(a?a); //~ ERROR no rules expected the token `?`
+    barstar!(a?); //~ ERROR no rules expected `?`
+    barstar!(a?a); //~ ERROR no rules expected `?`
     barstar!(a*);
     barstar!(*);
 }
diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.stderr b/tests/ui/macros/macro-at-most-once-rep-2018.stderr
index 696520b2826..f165a199b10 100644
--- a/tests/ui/macros/macro-at-most-once-rep-2018.stderr
+++ b/tests/ui/macros/macro-at-most-once-rep-2018.stderr
@@ -4,7 +4,7 @@ error: the `?` macro repetition operator does not take a separator
 LL |     ($(a),?) => {};
    |          ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:25:11
    |
 LL | macro_rules! foo {
@@ -15,7 +15,7 @@ LL |     foo!(a?);
    |
    = note: while trying to match sequence end
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:26:11
    |
 LL | macro_rules! foo {
@@ -26,7 +26,7 @@ LL |     foo!(a?a);
    |
    = note: while trying to match sequence end
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:27:11
    |
 LL | macro_rules! foo {
@@ -67,7 +67,7 @@ note: while trying to match `+`
 LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:31:15
    |
 LL | macro_rules! barplus {
@@ -82,7 +82,7 @@ note: while trying to match `+`
 LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:32:15
    |
 LL | macro_rules! barplus {
@@ -127,7 +127,7 @@ note: while trying to match `*`
 LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:38:15
    |
 LL | macro_rules! barstar {
@@ -142,7 +142,7 @@ note: while trying to match `*`
 LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:39:15
    |
 LL | macro_rules! barstar {
diff --git a/tests/ui/macros/macro-context.rs b/tests/ui/macros/macro-context.rs
index d09fdf118e6..a31470263a0 100644
--- a/tests/ui/macros/macro-context.rs
+++ b/tests/ui/macros/macro-context.rs
@@ -1,9 +1,9 @@
 // (typeof used because it's surprisingly hard to find an unparsed token after a stmt)
 macro_rules! m {
     () => ( i ; typeof );   //~ ERROR expected expression, found reserved keyword `typeof`
-                            //~| ERROR macro expansion ignores token `typeof`
-                            //~| ERROR macro expansion ignores token `;`
-                            //~| ERROR macro expansion ignores token `;`
+                            //~| ERROR macro expansion ignores reserved keyword `typeof`
+                            //~| ERROR macro expansion ignores `;`
+                            //~| ERROR macro expansion ignores `;`
                             //~| ERROR cannot find type `i` in this scope
                             //~| ERROR cannot find value `i` in this scope
                             //~| WARN trailing semicolon in macro
diff --git a/tests/ui/macros/macro-context.stderr b/tests/ui/macros/macro-context.stderr
index 7785f415946..4820a43f00c 100644
--- a/tests/ui/macros/macro-context.stderr
+++ b/tests/ui/macros/macro-context.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `;` and any following
+error: macro expansion ignores `;` and any tokens following
   --> $DIR/macro-context.rs:3:15
    |
 LL |     () => ( i ; typeof );
@@ -9,7 +9,7 @@ LL |     let a: m!();
    |
    = note: the usage of `m!` is likely invalid in type context
 
-error: macro expansion ignores token `typeof` and any following
+error: macro expansion ignores reserved keyword `typeof` and any tokens following
   --> $DIR/macro-context.rs:3:17
    |
 LL |     () => ( i ; typeof );
@@ -20,7 +20,7 @@ LL |     let i = m!();
    |
    = note: the usage of `m!` is likely invalid in expression context
 
-error: macro expansion ignores token `;` and any following
+error: macro expansion ignores `;` and any tokens following
   --> $DIR/macro-context.rs:3:15
    |
 LL |     () => ( i ; typeof );
diff --git a/tests/ui/macros/macro-in-expression-context.fixed b/tests/ui/macros/macro-in-expression-context.fixed
index f4d04ca37bf..7c830707ffd 100644
--- a/tests/ui/macros/macro-in-expression-context.fixed
+++ b/tests/ui/macros/macro-in-expression-context.fixed
@@ -11,7 +11,7 @@ macro_rules! foo {
         //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default
         assert_eq!("B", "B");
     }
-    //~^^ ERROR macro expansion ignores token `assert_eq` and any following
+    //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following
     //~| NOTE the usage of `foo!` is likely invalid in expression context
 }
 
diff --git a/tests/ui/macros/macro-in-expression-context.rs b/tests/ui/macros/macro-in-expression-context.rs
index 8921a056377..da95017aa5f 100644
--- a/tests/ui/macros/macro-in-expression-context.rs
+++ b/tests/ui/macros/macro-in-expression-context.rs
@@ -11,7 +11,7 @@ macro_rules! foo {
         //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default
         assert_eq!("B", "B");
     }
-    //~^^ ERROR macro expansion ignores token `assert_eq` and any following
+    //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following
     //~| NOTE the usage of `foo!` is likely invalid in expression context
 }
 
diff --git a/tests/ui/macros/macro-in-expression-context.stderr b/tests/ui/macros/macro-in-expression-context.stderr
index 2eee63f307a..43419f2678c 100644
--- a/tests/ui/macros/macro-in-expression-context.stderr
+++ b/tests/ui/macros/macro-in-expression-context.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `assert_eq` and any following
+error: macro expansion ignores `assert_eq` and any tokens following
   --> $DIR/macro-in-expression-context.rs:12:9
    |
 LL |         assert_eq!("B", "B");
diff --git a/tests/ui/macros/macro-non-lifetime.rs b/tests/ui/macros/macro-non-lifetime.rs
index 26e1f2afa91..3defffd2960 100644
--- a/tests/ui/macros/macro-non-lifetime.rs
+++ b/tests/ui/macros/macro-non-lifetime.rs
@@ -4,5 +4,5 @@ macro_rules! m { ($x:lifetime) => { } }
 
 fn main() {
     m!(a);
-    //~^ ERROR no rules expected the token `a`
+    //~^ ERROR no rules expected `a`
 }
diff --git a/tests/ui/macros/macro-non-lifetime.stderr b/tests/ui/macros/macro-non-lifetime.stderr
index 9ff3d741c01..35040a2229b 100644
--- a/tests/ui/macros/macro-non-lifetime.stderr
+++ b/tests/ui/macros/macro-non-lifetime.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `a`
+error: no rules expected `a`
   --> $DIR/macro-non-lifetime.rs:6:8
    |
 LL | macro_rules! m { ($x:lifetime) => { } }
diff --git a/tests/ui/macros/missing-comma.rs b/tests/ui/macros/missing-comma.rs
index 92f8a779505..64cfb0db31a 100644
--- a/tests/ui/macros/missing-comma.rs
+++ b/tests/ui/macros/missing-comma.rs
@@ -19,16 +19,16 @@ fn main() {
     println!("{}" a);
     //~^ ERROR expected `,`, found `a`
     foo!(a b);
-    //~^ ERROR no rules expected the token `b`
+    //~^ ERROR no rules expected `b`
     foo!(a, b, c, d e);
-    //~^ ERROR no rules expected the token `e`
+    //~^ ERROR no rules expected `e`
     foo!(a, b, c d, e);
-    //~^ ERROR no rules expected the token `d`
+    //~^ ERROR no rules expected `d`
     foo!(a, b, c d e);
-    //~^ ERROR no rules expected the token `d`
+    //~^ ERROR no rules expected `d`
     bar!(Level::Error, );
     //~^ ERROR unexpected end of macro invocation
     check!(<str as Debug>::fmt, "fmt");
     check!(<str as Debug>::fmt, "fmt",);
-    //~^ ERROR no rules expected the token `,`
+    //~^ ERROR no rules expected `,`
 }
diff --git a/tests/ui/macros/missing-comma.stderr b/tests/ui/macros/missing-comma.stderr
index 81877a29ed8..9913ba34919 100644
--- a/tests/ui/macros/missing-comma.stderr
+++ b/tests/ui/macros/missing-comma.stderr
@@ -4,7 +4,7 @@ error: expected `,`, found `a`
 LL |     println!("{}" a);
    |                   ^ expected `,`
 
-error: no rules expected the token `b`
+error: no rules expected `b`
   --> $DIR/missing-comma.rs:21:12
    |
 LL | macro_rules! foo {
@@ -21,7 +21,7 @@ note: while trying to match meta-variable `$a:ident`
 LL |     ($a:ident) => ();
    |      ^^^^^^^^
 
-error: no rules expected the token `e`
+error: no rules expected `e`
   --> $DIR/missing-comma.rs:23:21
    |
 LL | macro_rules! foo {
@@ -38,7 +38,7 @@ note: while trying to match meta-variable `$d:ident`
 LL |     ($a:ident, $b:ident, $c:ident, $d:ident) => ();
    |                                    ^^^^^^^^
 
-error: no rules expected the token `d`
+error: no rules expected `d`
   --> $DIR/missing-comma.rs:25:18
    |
 LL | macro_rules! foo {
@@ -55,7 +55,7 @@ note: while trying to match meta-variable `$c:ident`
 LL |     ($a:ident, $b:ident, $c:ident) => ();
    |                          ^^^^^^^^
 
-error: no rules expected the token `d`
+error: no rules expected `d`
   --> $DIR/missing-comma.rs:27:18
    |
 LL | macro_rules! foo {
@@ -85,7 +85,7 @@ note: while trying to match meta-variable `$arg:tt`
 LL |     ($lvl:expr, $($arg:tt)+) => {}
    |                   ^^^^^^^
 
-error: no rules expected the token `,`
+error: no rules expected `,`
   --> $DIR/missing-comma.rs:32:38
    |
 LL | macro_rules! check {
diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs
index 5f0d6b2f90e..a655b665103 100644
--- a/tests/ui/macros/nonterminal-matching.rs
+++ b/tests/ui/macros/nonterminal-matching.rs
@@ -16,7 +16,7 @@ macro complex_nonterminal($nt_item: item) {
         struct S;
     }
 
-    n!(a $nt_item b); //~ ERROR no rules expected the token `enum E {}`
+    n!(a $nt_item b); //~ ERROR no rules expected item `enum E {}`
 }
 
 simple_nonterminal!(a, 'a, (x, y, z)); // OK
@@ -29,10 +29,10 @@ macro_rules! foo {
     (ident $x:ident) => { bar!(ident $x); };
     (lifetime $x:lifetime) => { bar!(lifetime $x); };
     (tt $x:tt) => { bar!(tt $x); };
-    (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected the token `3`
-    (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected the token `4`
-    (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected the token `a::b::c`
-    (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected the token `let abc = 0`
+    (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected expression `3`
+    (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected literal `4`
+    (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected path `a::b::c`
+    (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected statement `let abc = 0`
 }
 
 macro_rules! bar {
diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr
index 3ee88b5f52e..e283dfcb8fd 100644
--- a/tests/ui/macros/nonterminal-matching.stderr
+++ b/tests/ui/macros/nonterminal-matching.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `enum E {}`
+error: no rules expected item `enum E {}`
   --> $DIR/nonterminal-matching.rs:19:10
    |
 LL |     macro n(a $nt_item b) {
@@ -10,7 +10,7 @@ LL |     n!(a $nt_item b);
 LL | complex_nonterminal!(enum E {});
    | ------------------------------- in this macro invocation
    |
-note: while trying to match `enum E {}`
+note: while trying to match item `enum E {}`
   --> $DIR/nonterminal-matching.rs:15:15
    |
 LL |     macro n(a $nt_item b) {
@@ -23,7 +23,7 @@ LL | complex_nonterminal!(enum E {});
    = help: try using `:tt` instead in the macro definition
    = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: no rules expected the token `3`
+error: no rules expected expression `3`
   --> $DIR/nonterminal-matching.rs:32:35
    |
 LL |     (expr $x:expr) => { bar!(expr $x); };
@@ -45,7 +45,7 @@ LL |     (expr 3) => {};
    = help: try using `:tt` instead in the macro definition
    = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: no rules expected the token `4`
+error: no rules expected literal `4`
   --> $DIR/nonterminal-matching.rs:33:44
    |
 LL |     (literal $x:literal) => { bar!(literal $x); };
@@ -67,7 +67,7 @@ LL |     (literal 4) => {};
    = help: try using `:tt` instead in the macro definition
    = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: no rules expected the token `a::b::c`
+error: no rules expected path `a::b::c`
   --> $DIR/nonterminal-matching.rs:34:35
    |
 LL |     (path $x:path) => { bar!(path $x); };
@@ -89,7 +89,7 @@ LL |     (path a::b::c) => {};
    = help: try using `:tt` instead in the macro definition
    = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: no rules expected the token `let abc = 0`
+error: no rules expected statement `let abc = 0`
   --> $DIR/nonterminal-matching.rs:35:35
    |
 LL |     (stmt $x:stmt) => { bar!(stmt $x); };
@@ -101,7 +101,7 @@ LL | macro_rules! bar {
 LL | foo!(stmt let abc = 0);
    | ---------------------- in this macro invocation
    |
-note: while trying to match `let`
+note: while trying to match keyword `let`
   --> $DIR/nonterminal-matching.rs:45:11
    |
 LL |     (stmt let abc = 0) => {};
diff --git a/tests/ui/macros/syntax-error-recovery.rs b/tests/ui/macros/syntax-error-recovery.rs
index f6178c137db..016e4def284 100644
--- a/tests/ui/macros/syntax-error-recovery.rs
+++ b/tests/ui/macros/syntax-error-recovery.rs
@@ -10,7 +10,7 @@ macro_rules! values {
     };
 }
 //~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)`
-//~| ERROR macro expansion ignores token `(String)` and any following
+//~| ERROR macro expansion ignores type `(String)` and any tokens following
 
 values!(STRING(1) as (String) => cfg(test),);
 //~^ ERROR expected one of `!` or `::`, found `<eof>`
diff --git a/tests/ui/macros/syntax-error-recovery.stderr b/tests/ui/macros/syntax-error-recovery.stderr
index 6218bf43a1e..3cfbd8ce82b 100644
--- a/tests/ui/macros/syntax-error-recovery.stderr
+++ b/tests/ui/macros/syntax-error-recovery.stderr
@@ -10,7 +10,7 @@ LL | values!(STRING(1) as (String) => cfg(test),);
    = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
    = note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: macro expansion ignores token `(String)` and any following
+error: macro expansion ignores type `(String)` and any tokens following
   --> $DIR/syntax-error-recovery.rs:7:26
    |
 LL |                 $token $($inner)? = $value,
diff --git a/tests/ui/macros/trace_faulty_macros.stderr b/tests/ui/macros/trace_faulty_macros.stderr
index 66d7b76bb07..10ad3faab16 100644
--- a/tests/ui/macros/trace_faulty_macros.stderr
+++ b/tests/ui/macros/trace_faulty_macros.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `bcd`
+error: no rules expected `bcd`
   --> $DIR/trace_faulty_macros.rs:7:26
    |
 LL | macro_rules! my_faulty_macro {
diff --git a/tests/ui/offset-of/offset-of-arg-count.rs b/tests/ui/offset-of/offset-of-arg-count.rs
index c86e61a61a7..f4c8b91d7da 100644
--- a/tests/ui/offset-of/offset-of-arg-count.rs
+++ b/tests/ui/offset-of/offset-of-arg-count.rs
@@ -3,7 +3,7 @@ use std::mem::offset_of;
 fn main() {
     offset_of!(NotEnoughArguments); //~ ERROR unexpected end of macro invocation
     offset_of!(NotEnoughArgumentsWithAComma, ); //~ ERROR unexpected end of macro invocation
-    offset_of!(Container, field, too many arguments); //~ ERROR no rules expected the token `too`
+    offset_of!(Container, field, too many arguments); //~ ERROR no rules expected `too`
     offset_of!(S, f); // compiles fine
     offset_of!(S, f,); // also compiles fine
     offset_of!(S, f.); //~ ERROR unexpected token: `)`
diff --git a/tests/ui/offset-of/offset-of-arg-count.stderr b/tests/ui/offset-of/offset-of-arg-count.stderr
index 4cb24b3d034..0772bb18e0c 100644
--- a/tests/ui/offset-of/offset-of-arg-count.stderr
+++ b/tests/ui/offset-of/offset-of-arg-count.stderr
@@ -16,7 +16,7 @@ LL |     offset_of!(NotEnoughArgumentsWithAComma, );
 note: while trying to match meta-variable `$fields:expr`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
 
-error: no rules expected the token `too`
+error: no rules expected `too`
   --> $DIR/offset-of-arg-count.rs:6:34
    |
 LL |     offset_of!(Container, field, too many arguments);
diff --git a/tests/ui/offset-of/offset-of-tuple.stderr b/tests/ui/offset-of/offset-of-tuple.stderr
index dd20859e04e..38ce49c9179 100644
--- a/tests/ui/offset-of/offset-of-tuple.stderr
+++ b/tests/ui/offset-of/offset-of-tuple.stderr
@@ -76,7 +76,7 @@ error: suffixes on a tuple index are invalid
 LL |     offset_of!((u8, u8), 1_u8);
    |                          ^^^^ invalid suffix `u8`
 
-error: no rules expected the token `+`
+error: no rules expected `+`
   --> $DIR/offset-of-tuple.rs:11:26
    |
 LL |     offset_of!((u8, u8), +1);
diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs
index 7a94c96b79d..fb227bf0e91 100644
--- a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs
+++ b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs
@@ -9,5 +9,5 @@ macro_rules! accept_pat {
     ($p:pat) => {};
 }
 
-accept_pat!(p | q); //~ ERROR no rules expected the token `|`
-accept_pat!(|p| q); //~ ERROR no rules expected the token `|`
+accept_pat!(p | q); //~ ERROR no rules expected `|`
+accept_pat!(|p| q); //~ ERROR no rules expected `|`
diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr
index acc2099bbc6..47dac84ee49 100644
--- a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr
+++ b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `|`
+error: no rules expected `|`
   --> $DIR/or-patterns-syntactic-fail-2018.rs:12:15
    |
 LL | macro_rules! accept_pat {
@@ -13,7 +13,7 @@ note: while trying to match meta-variable `$p:pat`
 LL |     ($p:pat) => {};
    |      ^^^^^^
 
-error: no rules expected the token `|`
+error: no rules expected `|`
   --> $DIR/or-patterns-syntactic-fail-2018.rs:13:13
    |
 LL | macro_rules! accept_pat {
diff --git a/tests/ui/parser/macro/macro-doc-comments-1.rs b/tests/ui/parser/macro/macro-doc-comments-1.rs
index 8d8103bb1e0..1aaa993e072 100644
--- a/tests/ui/parser/macro/macro-doc-comments-1.rs
+++ b/tests/ui/parser/macro/macro-doc-comments-1.rs
@@ -4,6 +4,6 @@ macro_rules! outer {
 
 outer! {
     //! Inner
-} //~^ ERROR no rules expected the token `!`
+} //~^ ERROR no rules expected `!`
 
 fn main() { }
diff --git a/tests/ui/parser/macro/macro-doc-comments-1.stderr b/tests/ui/parser/macro/macro-doc-comments-1.stderr
index 9d2d1bc0072..6b7e758980c 100644
--- a/tests/ui/parser/macro/macro-doc-comments-1.stderr
+++ b/tests/ui/parser/macro/macro-doc-comments-1.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `!`
+error: no rules expected `!`
   --> $DIR/macro-doc-comments-1.rs:6:5
    |
 LL | macro_rules! outer {
diff --git a/tests/ui/parser/macro/macro-doc-comments-2.rs b/tests/ui/parser/macro/macro-doc-comments-2.rs
index 8f33720ae80..2bee2435ef8 100644
--- a/tests/ui/parser/macro/macro-doc-comments-2.rs
+++ b/tests/ui/parser/macro/macro-doc-comments-2.rs
@@ -4,6 +4,6 @@ macro_rules! inner {
 
 inner! {
     /// Outer
-} //~^ ERROR no rules expected the token `[`
+} //~^ ERROR no rules expected `[`
 
 fn main() { }
diff --git a/tests/ui/parser/macro/macro-doc-comments-2.stderr b/tests/ui/parser/macro/macro-doc-comments-2.stderr
index 22efd995b46..02c12bf9591 100644
--- a/tests/ui/parser/macro/macro-doc-comments-2.stderr
+++ b/tests/ui/parser/macro/macro-doc-comments-2.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `[`
+error: no rules expected `[`
   --> $DIR/macro-doc-comments-2.rs:6:5
    |
 LL | macro_rules! inner {
diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.rs b/tests/ui/parser/macro/macro-expand-to-match-arm.rs
index db38fa0d7bc..0e27836b718 100644
--- a/tests/ui/parser/macro/macro-expand-to-match-arm.rs
+++ b/tests/ui/parser/macro/macro-expand-to-match-arm.rs
@@ -1,7 +1,7 @@
 macro_rules! arm {
     ($pattern:pat => $block:block) => {
         $pattern => $block
-        //~^ ERROR macro expansion ignores token `=>` and any following
+        //~^ ERROR macro expansion ignores `=>` and any tokens following
         //~| NOTE the usage of `arm!` is likely invalid in pattern context
         //~| NOTE macros cannot expand to match arms
     };
diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.stderr b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr
index e3e7ff89c81..1927d80fd72 100644
--- a/tests/ui/parser/macro/macro-expand-to-match-arm.stderr
+++ b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `=>` and any following
+error: macro expansion ignores `=>` and any tokens following
   --> $DIR/macro-expand-to-match-arm.rs:3:18
    |
 LL |         $pattern => $block
diff --git a/tests/ui/parser/macro/macro-incomplete-parse.rs b/tests/ui/parser/macro/macro-incomplete-parse.rs
index 544e4aa7b1b..612196aa4b2 100644
--- a/tests/ui/parser/macro/macro-incomplete-parse.rs
+++ b/tests/ui/parser/macro/macro-incomplete-parse.rs
@@ -2,7 +2,7 @@ macro_rules! ignored_item {
     () => {
         fn foo() {}
         fn bar() {}
-        , //~ ERROR macro expansion ignores token `,`
+        , //~ ERROR macro expansion ignores `,`
     }
 }
 
@@ -13,7 +13,7 @@ macro_rules! ignored_expr {
 }
 
 macro_rules! ignored_pat {
-    () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,`
+    () => ( 1, 2 ) //~ ERROR macro expansion ignores `,`
 }
 
 ignored_item!();
diff --git a/tests/ui/parser/macro/macro-incomplete-parse.stderr b/tests/ui/parser/macro/macro-incomplete-parse.stderr
index 707417b725e..096b5f718ae 100644
--- a/tests/ui/parser/macro/macro-incomplete-parse.stderr
+++ b/tests/ui/parser/macro/macro-incomplete-parse.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `,` and any following
+error: macro expansion ignores `,` and any tokens following
   --> $DIR/macro-incomplete-parse.rs:5:9
    |
 LL |         ,
@@ -20,7 +20,7 @@ LL |     ignored_expr!();
    |
    = note: this error originates in the macro `ignored_expr` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: macro expansion ignores token `,` and any following
+error: macro expansion ignores `,` and any tokens following
   --> $DIR/macro-incomplete-parse.rs:16:14
    |
 LL |     () => ( 1, 2 )
diff --git a/tests/ui/parser/macro/trait-non-item-macros.rs b/tests/ui/parser/macro/trait-non-item-macros.rs
index 97fb564bf64..e93000193b6 100644
--- a/tests/ui/parser/macro/trait-non-item-macros.rs
+++ b/tests/ui/parser/macro/trait-non-item-macros.rs
@@ -1,7 +1,7 @@
 macro_rules! bah {
     ($a:expr) => {
         $a
-    }; //~^ ERROR macro expansion ignores token `2` and any following
+    }; //~^ ERROR macro expansion ignores expression `2` and any tokens following
 }
 
 trait Bar {
diff --git a/tests/ui/parser/macro/trait-non-item-macros.stderr b/tests/ui/parser/macro/trait-non-item-macros.stderr
index db20e6b24aa..1a828483778 100644
--- a/tests/ui/parser/macro/trait-non-item-macros.stderr
+++ b/tests/ui/parser/macro/trait-non-item-macros.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `2` and any following
+error: macro expansion ignores expression `2` and any tokens following
   --> $DIR/trait-non-item-macros.rs:3:9
    |
 LL |         $a
diff --git a/tests/ui/proc-macro/attr-invalid-exprs.rs b/tests/ui/proc-macro/attr-invalid-exprs.rs
index 3d8806ee800..ec0b79469a4 100644
--- a/tests/ui/proc-macro/attr-invalid-exprs.rs
+++ b/tests/ui/proc-macro/attr-invalid-exprs.rs
@@ -13,7 +13,7 @@ fn main() {
     //~^ ERROR expected expression, found end of macro arguments
 
     let _ = #[duplicate] "Hello, world!";
-    //~^ ERROR macro expansion ignores token `,` and any following
+    //~^ ERROR macro expansion ignores `,` and any tokens following
 
     let _ = {
         #[no_output]
@@ -22,7 +22,7 @@ fn main() {
 
     let _ = {
         #[duplicate]
-        //~^ ERROR macro expansion ignores token `,` and any following
+        //~^ ERROR macro expansion ignores `,` and any tokens following
         "Hello, world!"
     };
 }
diff --git a/tests/ui/proc-macro/attr-invalid-exprs.stderr b/tests/ui/proc-macro/attr-invalid-exprs.stderr
index f96939bb6ef..0d500c87145 100644
--- a/tests/ui/proc-macro/attr-invalid-exprs.stderr
+++ b/tests/ui/proc-macro/attr-invalid-exprs.stderr
@@ -4,7 +4,7 @@ error: expected expression, found end of macro arguments
 LL |     let _ = #[no_output] "Hello, world!";
    |             ^^^^^^^^^^^^
 
-error: macro expansion ignores token `,` and any following
+error: macro expansion ignores `,` and any tokens following
   --> $DIR/attr-invalid-exprs.rs:15:13
    |
 LL |     let _ = #[duplicate] "Hello, world!";
@@ -16,7 +16,7 @@ help: you might be missing a semicolon here
 LL |     let _ = #[duplicate]; "Hello, world!";
    |                         +
 
-error: macro expansion ignores token `,` and any following
+error: macro expansion ignores `,` and any tokens following
   --> $DIR/attr-invalid-exprs.rs:24:9
    |
 LL |         #[duplicate]
diff --git a/tests/ui/proc-macro/expand-expr.rs b/tests/ui/proc-macro/expand-expr.rs
index 5f7375d7450..e06ddc51a29 100644
--- a/tests/ui/proc-macro/expand-expr.rs
+++ b/tests/ui/proc-macro/expand-expr.rs
@@ -114,8 +114,8 @@ expand_expr_fail!(echo_pm!($)); //~ ERROR: expected expression, found `$`
 
 // We get errors reported and recover during macro expansion if the macro
 // doesn't produce a valid expression.
-expand_expr_is!("string", echo_tts!("string"; hello)); //~ ERROR: macro expansion ignores token `hello` and any following
-expand_expr_is!("string", echo_pm!("string"; hello)); //~ ERROR: macro expansion ignores token `;` and any following
+expand_expr_is!("string", echo_tts!("string"; hello)); //~ ERROR: macro expansion ignores `hello` and any tokens following
+expand_expr_is!("string", echo_pm!("string"; hello)); //~ ERROR: macro expansion ignores `;` and any tokens following
 
 // For now, fail if a non-literal expression is expanded.
 expand_expr_fail!(arbitrary_expression() + "etc");
diff --git a/tests/ui/proc-macro/expand-expr.stderr b/tests/ui/proc-macro/expand-expr.stderr
index 2b92472e5ab..8b1df177cfa 100644
--- a/tests/ui/proc-macro/expand-expr.stderr
+++ b/tests/ui/proc-macro/expand-expr.stderr
@@ -22,7 +22,7 @@ error: expected expression, found `$`
 LL | expand_expr_fail!(echo_pm!($));
    |                            ^ expected expression
 
-error: macro expansion ignores token `hello` and any following
+error: macro expansion ignores `hello` and any tokens following
   --> $DIR/expand-expr.rs:117:47
    |
 LL | expand_expr_is!("string", echo_tts!("string"; hello));
@@ -34,7 +34,7 @@ help: you might be missing a semicolon here
 LL | expand_expr_is!("string", echo_tts!("string"; hello););
    |                                                     +
 
-error: macro expansion ignores token `;` and any following
+error: macro expansion ignores `;` and any tokens following
   --> $DIR/expand-expr.rs:118:44
    |
 LL | expand_expr_is!("string", echo_pm!("string"; hello));
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs
index b8c0eb3e6d6..4b2fc4a03b6 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs
@@ -68,7 +68,7 @@ fn _macros() {
         _ => {}
     }
     use_expr!(let 0 = 1);
-    //~^ ERROR no rules expected the token `let`
+    //~^ ERROR no rules expected keyword `let`
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr
index 2341dbbbdbd..1c710b04897 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr
@@ -131,7 +131,7 @@ LL |     use_expr!((let 0 = 1));
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
-error: no rules expected the token `let`
+error: no rules expected keyword `let`
   --> $DIR/feature-gate.rs:70:15
    |
 LL |     macro_rules! use_expr {
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs
index bca7564efd8..2087fc42cf1 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs
@@ -54,7 +54,7 @@ fn _macros() {
     #[cfg(FALSE)] (let 0 = 1);
     //~^ ERROR expected expression, found `let` statement
     use_expr!(let 0 = 1);
-    //~^ ERROR no rules expected the token `let`
+    //~^ ERROR no rules expected keyword `let`
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr
index 2b1a49be3da..7c874ae78a8 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr
@@ -14,7 +14,7 @@ LL |     noop_expr!((let 0 = 1));
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
-error: no rules expected the token `let`
+error: no rules expected keyword `let`
   --> $DIR/feature-gate.rs:56:15
    |
 LL |     macro_rules! use_expr {
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr
index be4a5231558..130d0296c5e 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr
@@ -111,5 +111,23 @@ LL |     while let Some(ref first) = opt && let second = first && let _third = s
    = note: these patterns will always match
    = help: consider moving them into the body
 
-error: aborting due to 12 previous errors
+error: trailing irrefutable pattern in let chain
+  --> $DIR/irrefutable-lets.rs:87:12
+   |
+LL |         && let x = &opt
+   |            ^^^^^^^^^^^^
+   |
+   = note: this pattern will always match
+   = help: consider moving it into the body
+
+error: leading irrefutable pattern in let chain
+  --> $DIR/irrefutable-lets.rs:93:12
+   |
+LL |         if let x = opt.clone().map(|_| 1)
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this pattern will always match
+   = help: consider moving it outside of the construct
+
+error: aborting due to 14 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs
index bd4df337614..e7d69f89773 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs
@@ -75,4 +75,24 @@ fn main() {
         && let Range { start: local_start, end: _ } = first
         && let None = local_start {
     }
+
+    // No error. An extra nesting level would be required for the `else if`.
+    if opt == Some(None..None) {
+    } else if let x = opt.clone().map(|_| 1)
+        && x == Some(1)
+    {}
+
+    if opt == Some(None..None) {
+    } else if opt.is_some()
+        && let x = &opt
+        //[disallowed]~^ ERROR trailing irrefutable pattern in let chain
+    {}
+
+    if opt == Some(None..None) {
+    } else {
+        if let x = opt.clone().map(|_| 1)
+        //[disallowed]~^ ERROR leading irrefutable pattern in let chain
+            && x == Some(1)
+        {}
+    }
 }
diff --git a/tests/ui/underscore-ident-matcher.rs b/tests/ui/underscore-ident-matcher.rs
index bddc8c80a7b..77ec70d43d5 100644
--- a/tests/ui/underscore-ident-matcher.rs
+++ b/tests/ui/underscore-ident-matcher.rs
@@ -5,5 +5,5 @@ macro_rules! identity {
 }
 
 fn main() {
-    let identity!(_) = 10; //~ ERROR no rules expected the token `_`
+    let identity!(_) = 10; //~ ERROR no rules expected reserved identifier `_`
 }
diff --git a/tests/ui/underscore-ident-matcher.stderr b/tests/ui/underscore-ident-matcher.stderr
index a663f34cde1..0c3f980cf6c 100644
--- a/tests/ui/underscore-ident-matcher.stderr
+++ b/tests/ui/underscore-ident-matcher.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `_`
+error: no rules expected reserved identifier `_`
   --> $DIR/underscore-ident-matcher.rs:8:19
    |
 LL | macro_rules! identity {