about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock59
-rw-r--r--compiler/rustc_ast/src/ast.rs3
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs9
-rw-r--r--compiler/rustc_ast/src/util/parser.rs2
-rw-r--r--compiler/rustc_ast/src/visit.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs7
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs12
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs25
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs15
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs6
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl2
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs22
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath.rs36
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath/tests.rs35
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs9
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs15
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs5
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs12
-rw-r--r--compiler/rustc_errors/Cargo.toml1
-rw-r--r--compiler/rustc_errors/src/emitter.rs251
-rw-r--r--compiler/rustc_errors/src/json.rs32
-rw-r--r--compiler/rustc_errors/src/lib.rs13
-rw-r--r--compiler/rustc_expand/Cargo.toml1
-rw-r--r--compiler/rustc_expand/src/tests.rs33
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs8
-rw-r--r--compiler/rustc_hir/src/intravisit.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs28
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/variance/terms.rs8
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs25
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs86
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/rvalue_scopes.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs2
-rw-r--r--compiler/rustc_infer/src/infer/at.rs28
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs10
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs17
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs2
-rw-r--r--compiler/rustc_lint/messages.ftl7
-rw-r--r--compiler/rustc_lint/src/builtin.rs90
-rw-r--r--compiler/rustc_lint/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/lints.rs10
-rw-r--r--compiler/rustc_lint/src/non_ascii_idents.rs1
-rw-r--r--compiler/rustc_lint/src/unused.rs4
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs40
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs10
-rw-r--r--compiler/rustc_middle/src/hir/place.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs6
-rw-r--r--compiler/rustc_middle/src/traits/solve/cache.rs100
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect.rs13
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect/format.rs7
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs13
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs3
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs13
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs11
-rw-r--r--compiler/rustc_passes/src/liveness.rs2
-rw-r--r--compiler/rustc_query_system/Cargo.toml2
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs3
-rw-r--r--compiler/rustc_query_system/src/query/job.rs23
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_session/src/session.rs34
-rw-r--r--compiler/rustc_span/src/edit_distance.rs4
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs2
-rw-r--r--compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs2
-rw-r--r--compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/alias_relate.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs77
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonicalize.rs94
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs255
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs171
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs5
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs20
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalize.rs9
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs18
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/mod.rs389
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs120
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs182
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs35
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs87
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs92
-rw-r--r--compiler/rustc_type_ir/src/lib.rs5
-rw-r--r--src/bootstrap/config.rs3
-rw-r--r--src/librustdoc/core.rs20
-rw-r--r--src/librustdoc/doctest.rs46
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css2
-rw-r--r--src/librustdoc/html/static/css/themes/light.css2
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_next.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/temporary_assignment.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs4
-rw-r--r--src/tools/compiletest/src/runtest.rs9
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs5
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs5
-rw-r--r--src/tools/rustfmt/src/expr.rs4
-rw-r--r--src/tools/rustfmt/src/matches.rs2
-rw-r--r--src/tools/rustfmt/src/parse/session.rs15
-rw-r--r--src/tools/rustfmt/src/utils.rs4
-rw-r--r--src/tools/tidy/src/deps.rs7
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/rustdoc-gui/run-on-hover.goml12
-rw-r--r--tests/rustdoc-json/type/inherent_associated_type_bound.rs17
-rw-r--r--tests/rustdoc-json/type/inherent_associated_type_projections.rs12
-rw-r--r--tests/rustdoc/inherent-projections.rs10
-rw-r--r--tests/ui/array-slice-vec/slice-2.stderr16
-rw-r--r--tests/ui/associated-inherent-types/issue-111879-0.rs4
-rw-r--r--tests/ui/associated-inherent-types/issue-111879-0.stderr6
-rw-r--r--tests/ui/associated-inherent-types/late-bound-regions.rs4
-rw-r--r--tests/ui/associated-inherent-types/late-bound-regions.stderr2
-rw-r--r--tests/ui/associated-inherent-types/not-found-self-type-differs.alias.stderr16
-rw-r--r--tests/ui/associated-inherent-types/not-found-self-type-differs.local.stderr16
-rw-r--r--tests/ui/associated-inherent-types/not-found-self-type-differs.rs9
-rw-r--r--tests/ui/associated-inherent-types/not-found-self-type-differs.stderr29
-rw-r--r--tests/ui/associated-inherent-types/substitute-params-bad.rs2
-rw-r--r--tests/ui/associated-inherent-types/substitute-params.rs3
-rw-r--r--tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs4
-rw-r--r--tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.stderr55
-rw-r--r--tests/ui/async-await/track-caller/async-block.afn.stderr30
-rw-r--r--tests/ui/async-await/track-caller/async-block.nofeat.stderr30
-rw-r--r--tests/ui/async-await/track-caller/async-block.rs18
-rw-r--r--tests/ui/async-await/track-caller/async-block.stderr12
-rw-r--r--tests/ui/async-await/track-caller/async-closure-gate.afn.stderr57
-rw-r--r--tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr57
-rw-r--r--tests/ui/async-await/track-caller/async-closure-gate.rs41
-rw-r--r--tests/ui/async-await/track-caller/async-closure-gate.stderr12
-rw-r--r--tests/ui/async-await/track-caller/panic-track-caller.cls.stderr31
-rw-r--r--tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr14
-rw-r--r--tests/ui/async-await/track-caller/panic-track-caller.rs46
-rw-r--r--tests/ui/borrowck/suggest-local-var-for-vector.stderr10
-rw-r--r--tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr10
-rw-r--r--tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr28
-rw-r--r--tests/ui/consts/issue-94675.stderr4
-rw-r--r--tests/ui/dst/issue-113447.fixed25
-rw-r--r--tests/ui/dst/issue-113447.rs25
-rw-r--r--tests/ui/dst/issue-113447.stderr25
-rw-r--r--tests/ui/dyn-star/param-env-region-infer.current.stderr2
-rw-r--r--tests/ui/dyn-star/param-env-region-infer.next.stderr30
-rw-r--r--tests/ui/dyn-star/param-env-region-infer.rs9
-rw-r--r--tests/ui/error-codes/E0608.stderr4
-rw-r--r--tests/ui/impl-trait/nested-rpit-hrtb-2.rs9
-rw-r--r--tests/ui/impl-trait/nested-rpit-hrtb-2.stderr12
-rw-r--r--tests/ui/indexing/index-bot.rs (renamed from tests/ui/index-bot.rs)0
-rw-r--r--tests/ui/indexing/index-bot.stderr (renamed from tests/ui/index-bot.stderr)4
-rw-r--r--tests/ui/indexing/index-help.rs (renamed from tests/ui/index-help.rs)0
-rw-r--r--tests/ui/indexing/index-help.stderr (renamed from tests/ui/index-help.stderr)0
-rw-r--r--tests/ui/indexing/index_message.rs (renamed from tests/ui/index_message.rs)0
-rw-r--r--tests/ui/indexing/index_message.stderr (renamed from tests/ui/index_message.stderr)4
-rw-r--r--tests/ui/indexing/indexing-requires-a-uint.rs (renamed from tests/ui/indexing-requires-a-uint.rs)0
-rw-r--r--tests/ui/indexing/indexing-requires-a-uint.stderr (renamed from tests/ui/indexing-requires-a-uint.stderr)0
-rw-r--r--tests/ui/indexing/indexing-spans-caller-location.rs27
-rw-r--r--tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr2
-rw-r--r--tests/ui/invalid/issue-114435-layout-type-err.rs44
-rw-r--r--tests/ui/invalid/issue-114435-layout-type-err.stderr8
-rw-r--r--tests/ui/issues/issue-27842.stderr12
-rw-r--r--tests/ui/issues/issue-40861.stderr4
-rw-r--r--tests/ui/lazy-type-alias/variance.rs38
-rw-r--r--tests/ui/lint/lint-unconditional-recursion.stderr2
-rw-r--r--tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs4
-rw-r--r--tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr12
-rw-r--r--tests/ui/moves/use_of_moved_value_clone_suggestions.stderr2
-rw-r--r--tests/ui/privacy/sealed-traits/sealed-trait-local.stderr2
-rw-r--r--tests/ui/proc-macro/meta-macro-hygiene.stdout2
-rw-r--r--tests/ui/proc-macro/nonterminal-token-hygiene.stdout2
-rw-r--r--tests/ui/span/suggestion-non-ascii.stderr4
-rw-r--r--tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.rs32
-rw-r--r--tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.stderr23
-rw-r--r--tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.rs69
-rw-r--r--tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.stderr16
-rw-r--r--tests/ui/traits/new-solver/overflow/global-cache.rs23
-rw-r--r--tests/ui/traits/new-solver/overflow/global-cache.stderr16
-rw-r--r--tests/ui/traits/trait-upcasting/fewer-associated.rs25
-rw-r--r--tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr14
-rw-r--r--tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr14
-rw-r--r--tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs23
-rw-r--r--tests/ui/traits/trait-upcasting/normalization.rs20
-rw-r--r--tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs15
-rw-r--r--tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr35
-rw-r--r--tests/ui/typeck/issue-112252-ptr-arithmetics-help.stderr4
-rw-r--r--tests/ui/typeck/issue-114423-ice-regression-in-suggestion.rs15
-rw-r--r--tests/ui/typeck/issue-114423-ice-regression-in-suggestion.stderr52
235 files changed, 2822 insertions, 1668 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9f6df6e14c6..7cde7989bc0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -831,6 +831,41 @@ dependencies = [
 ]
 
 [[package]]
+name = "darling"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 2.0.27",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 2.0.27",
+]
+
+[[package]]
 name = "datafrog"
 version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -870,6 +905,18 @@ dependencies = [
 ]
 
 [[package]]
+name = "derive_setters"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.27",
+]
+
+[[package]]
 name = "diff"
 version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1741,6 +1788,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
 name = "idna"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3416,7 +3469,7 @@ dependencies = [
  "libc",
  "measureme",
  "memmap2",
- "parking_lot 0.11.2",
+ "parking_lot 0.12.1",
  "rustc-hash",
  "rustc-rayon",
  "rustc-rayon-core",
@@ -3524,6 +3577,7 @@ name = "rustc_errors"
 version = "0.0.0"
 dependencies = [
  "annotate-snippets",
+ "derive_setters",
  "rustc_ast",
  "rustc_ast_pretty",
  "rustc_data_structures",
@@ -3566,6 +3620,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "smallvec",
+ "termcolor",
  "thin-vec",
  "tracing",
 ]
@@ -4135,7 +4190,7 @@ dependencies = [
 name = "rustc_query_system"
 version = "0.0.0"
 dependencies = [
- "parking_lot 0.11.2",
+ "parking_lot 0.12.1",
  "rustc-rayon-core",
  "rustc_ast",
  "rustc_data_structures",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 2a268c2da85..f2e90fd8eed 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1462,7 +1462,8 @@ pub enum ExprKind {
     /// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
     Field(P<Expr>, Ident),
     /// An indexing operation (e.g., `foo[2]`).
-    Index(P<Expr>, P<Expr>),
+    /// The span represents the span of the `[2]`, including brackets.
+    Index(P<Expr>, P<Expr>, Span),
     /// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assignment).
     Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits),
     /// An underscore, used in destructuring assignment to ignore a value.
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 84b56efd325..bae3979fbf9 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1400,7 +1400,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
             fn_decl,
             body,
             fn_decl_span,
-            fn_arg_span: _,
+            fn_arg_span,
         }) => {
             vis.visit_closure_binder(binder);
             visit_constness(constness, vis);
@@ -1408,6 +1408,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
             vis.visit_fn_decl(fn_decl);
             vis.visit_expr(body);
             vis.visit_span(fn_decl_span);
+            vis.visit_span(fn_arg_span);
         }
         ExprKind::Block(blk, label) => {
             vis.visit_block(blk);
@@ -1420,9 +1421,10 @@ pub fn noop_visit_expr<T: MutVisitor>(
             vis.visit_expr(expr);
             vis.visit_span(await_kw_span);
         }
-        ExprKind::Assign(el, er, _) => {
+        ExprKind::Assign(el, er, span) => {
             vis.visit_expr(el);
             vis.visit_expr(er);
+            vis.visit_span(span);
         }
         ExprKind::AssignOp(_op, el, er) => {
             vis.visit_expr(el);
@@ -1432,9 +1434,10 @@ pub fn noop_visit_expr<T: MutVisitor>(
             vis.visit_expr(el);
             vis.visit_ident(ident);
         }
-        ExprKind::Index(el, er) => {
+        ExprKind::Index(el, er, brackets_span) => {
             vis.visit_expr(el);
             vis.visit_expr(er);
+            vis.visit_span(brackets_span);
         }
         ExprKind::Range(e1, e2, _lim) => {
             visit_opt(e1, |e1| vis.visit_expr(e1));
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 096077e09bf..d3e43e20235 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -390,7 +390,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
         | ast::ExprKind::Cast(x, _)
         | ast::ExprKind::Type(x, _)
         | ast::ExprKind::Field(x, _)
-        | ast::ExprKind::Index(x, _) => {
+        | ast::ExprKind::Index(x, _, _) => {
             // &X { y: 1 }, X { y: 1 }.y
             contains_exterior_struct_lit(x)
         }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index aed24e11c4e..6d474de2d15 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -885,7 +885,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_expr(subexpression);
             visitor.visit_ident(*ident);
         }
-        ExprKind::Index(main_expression, index_expression) => {
+        ExprKind::Index(main_expression, index_expression, _) => {
             visitor.visit_expr(main_expression);
             visitor.visit_expr(index_expression)
         }
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 0954cf03da9..42d0998d162 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -240,8 +240,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ExprKind::Field(el, ident) => {
                     hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident))
                 }
-                ExprKind::Index(el, er) => {
-                    hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er))
+                ExprKind::Index(el, er, brackets_span) => {
+                    hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er), *brackets_span)
                 }
                 ExprKind::Range(Some(e1), Some(e2), RangeLimits::Closed) => {
                     self.lower_expr_range_closed(e.span, e1, e2)
@@ -657,14 +657,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     /// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
-    /// `inner_hir_id` in case the `closure_track_caller` feature is enabled.
+    /// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.
     pub(super) fn maybe_forward_track_caller(
         &mut self,
         span: Span,
         outer_hir_id: hir::HirId,
         inner_hir_id: hir::HirId,
     ) {
-        if self.tcx.features().closure_track_caller
+        if self.tcx.features().async_fn_track_caller
             && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
             && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
         {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 5a0474dbc01..df73c721ade 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -56,6 +56,11 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
         owner: NodeId,
         f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
     ) {
+        let allow_gen_future = Some(if self.tcx.features().async_fn_track_caller {
+            [sym::gen_future, sym::closure_track_caller][..].into()
+        } else {
+            [sym::gen_future][..].into()
+        });
         let mut lctx = LoweringContext {
             // Pseudo-globals.
             tcx: self.tcx,
@@ -83,7 +88,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
             impl_trait_defs: Vec::new(),
             impl_trait_bounds: Vec::new(),
             allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
-            allow_gen_future: Some([sym::gen_future, sym::closure_track_caller][..].into()),
+            allow_gen_future,
             generics_def_id_map: Default::default(),
         };
         lctx.with_hir_id_owner(owner, |lctx| f(lctx));
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 8767bbcb210..39741a03930 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -477,7 +477,7 @@ impl<'a> State<'a> {
                 self.word(".");
                 self.print_ident(*ident);
             }
-            ast::ExprKind::Index(expr, index) => {
+            ast::ExprKind::Index(expr, index, _) => {
                 self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
                 self.word("[");
                 self.print_expr(index);
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 28c0a444fc8..fe4a45b3898 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -751,9 +751,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 )
                 .must_apply_modulo_regions()
         {
+            let msg = if let ty::Adt(def, _) = ty.kind()
+                && [
+                    tcx.get_diagnostic_item(sym::Arc),
+                    tcx.get_diagnostic_item(sym::Rc),
+                ].contains(&Some(def.did()))
+            {
+                "clone the value to increment its reference count"
+            } else {
+                "consider cloning the value if the performance cost is acceptable"
+            };
             err.span_suggestion_verbose(
                 span.shrink_to_hi(),
-                "consider cloning the value if the performance cost is acceptable",
+                msg,
                 suggestion,
                 Applicability::MachineApplicable,
             );
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index c92f32071f4..c66a2447356 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -79,7 +79,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
                         | hir::ExprKind::Unary(hir::UnOp::Deref, inner)
                         | hir::ExprKind::Field(inner, _)
                         | hir::ExprKind::MethodCall(_, inner, _, _)
-                        | hir::ExprKind::Index(inner, _) = &expr.kind
+                        | hir::ExprKind::Index(inner, _, _) = &expr.kind
                     {
                         expr = inner;
                     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 3c32121a51a..d62541daf07 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -567,7 +567,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         }
                     };
                     if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind
-                        && let hir::ExprKind::Index(val, index) = place.kind
+                        && let hir::ExprKind::Index(val, index, _) = place.kind
                         && (expr.span == self.assign_span || place.span == self.assign_span)
                     {
                         // val[index] = rv;
@@ -620,7 +620,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         );
                         self.suggested = true;
                     } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
-                        && let hir::ExprKind::Index(val, index) = receiver.kind
+                        && let hir::ExprKind::Index(val, index, _) = receiver.kind
                         && expr.span == self.assign_span
                     {
                         // val[index].path(args..);
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 30dfb2d919a..b8cd94e5422 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -784,13 +784,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// is considered a *lower bound*. If possible, we will modify
     /// the constraint to set it equal to one of the option regions.
     /// If we make any changes, returns true, else false.
+    ///
+    /// This function only adds the member constraints to the region graph,
+    /// it does not check them. They are later checked in
+    /// `check_member_constraints` after the region graph has been computed.
     #[instrument(skip(self, member_constraint_index), level = "debug")]
     fn apply_member_constraint(
         &mut self,
         scc: ConstraintSccIndex,
         member_constraint_index: NllMemberConstraintIndex,
         choice_regions: &[ty::RegionVid],
-    ) -> bool {
+    ) {
+        // Lazily compute the reverse graph, we'll need it later.
+        self.compute_reverse_scc_graph();
+
         // Create a mutable vector of the options. We'll try to winnow
         // them down.
         let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec();
@@ -805,10 +812,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             *c_r = self.scc_representatives[scc];
         }
 
-        // The 'member region' in a member constraint is part of the
-        // hidden type, which must be in the root universe. Therefore,
-        // it cannot have any placeholders in its value.
-        assert!(self.scc_universes[scc] == ty::UniverseIndex::ROOT);
+        // If the member region lives in a higher universe, we currently choose
+        // the most conservative option by leaving it unchanged.
+        if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
+            return;
+        }
         debug_assert!(
             self.scc_values.placeholders_contained_in(scc).next().is_none(),
             "scc {:?} in a member constraint has placeholder value: {:?}",
@@ -832,7 +840,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // free region that must outlive the member region `R0` (`UB:
         // R0`). Therefore, we need only keep an option `O` if `UB: O`
         // for all UB.
-        self.compute_reverse_scc_graph();
         let universal_region_relations = &self.universal_region_relations;
         for ub in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
             debug!(?ub);
@@ -867,7 +874,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             }
         }) else {
             debug!("no unique minimum choice");
-            return false;
+            return;
         };
 
         let min_choice_scc = self.constraint_sccs.scc(min_choice);
@@ -878,10 +885,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 min_choice,
                 member_constraint_index,
             });
-
-            true
-        } else {
-            false
         }
     }
 
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 90bde88f792..68dddd65acb 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -185,6 +185,21 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     {
         tcx.fold_regions(ty, |region, _| match *region {
             ty::ReVar(vid) => {
+                let scc = self.constraint_sccs.scc(vid);
+
+                // Special handling of higher-ranked regions.
+                if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
+                    match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
+                        // If the region contains a single placeholder then they're equal.
+                        Some((0, placeholder)) => {
+                            return ty::Region::new_placeholder(tcx, placeholder);
+                        }
+
+                        // Fallback: this will produce a cryptic error message.
+                        _ => return region,
+                    }
+                }
+
                 // Find something that we can name
                 let upper_bound = self.approx_universal_upper_bound(vid);
                 let upper_bound = &self.definitions[upper_bound];
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index abb11ce7396..50d875dfae9 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -498,14 +498,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
 
     /// Checks that the types internal to the `place` match up with
     /// what would be expected.
+    #[instrument(level = "debug", skip(self, location), ret)]
     fn sanitize_place(
         &mut self,
         place: &Place<'tcx>,
         location: Location,
         context: PlaceContext,
     ) -> PlaceTy<'tcx> {
-        debug!("sanitize_place: {:?}", place);
-
         let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty);
 
         for elem in place.projection.iter() {
@@ -608,7 +607,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         }
     }
 
-    #[instrument(skip(self), level = "debug")]
+    #[instrument(skip(self, location), ret, level = "debug")]
     fn sanitize_projection(
         &mut self,
         base: PlaceTy<'tcx>,
@@ -617,7 +616,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         location: Location,
         context: PlaceContext,
     ) -> PlaceTy<'tcx> {
-        debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place);
         let tcx = self.tcx();
         let base_ty = base.ty;
         match pi {
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 79fae7f92f1..8d8db4c13fa 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -227,3 +227,5 @@ builtin_macros_unexpected_lit = expected path to a trait, found literal
     .label = not a trait
     .str_lit = try using `#[derive({$sym})]`
     .other = for example, write `#[derive(Debug)]` for `Debug`
+
+builtin_macros_unnameable_test_items = cannot test inner items
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index cbf115127cf..bda473120ed 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -237,7 +237,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
             ExprKind::If(local_expr, _, _) => {
                 self.manage_cond_expr(local_expr);
             }
-            ExprKind::Index(prefix, suffix) => {
+            ExprKind::Index(prefix, suffix, _) => {
                 self.manage_cond_expr(prefix);
                 self.manage_cond_expr(suffix);
             }
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 81b618548da..507b74c2437 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -4,10 +4,12 @@ use rustc_ast as ast;
 use rustc_ast::entry::EntryPointType;
 use rustc_ast::mut_visit::{ExpectOne, *};
 use rustc_ast::ptr::P;
+use rustc_ast::visit::{walk_item, Visitor};
 use rustc_ast::{attr, ModKind};
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
 use rustc_feature::Features;
+use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS;
 use rustc_session::Session;
 use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -137,11 +139,31 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
             let prev_tests = mem::take(&mut self.tests);
             noop_visit_item_kind(&mut item.kind, self);
             self.add_test_cases(item.id, span, prev_tests);
+        } else {
+            // But in those cases, we emit a lint to warn the user of these missing tests.
+            walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item);
         }
         smallvec![P(item)]
     }
 }
 
+struct InnerItemLinter<'a> {
+    sess: &'a Session,
+}
+
+impl<'a> Visitor<'a> for InnerItemLinter<'_> {
+    fn visit_item(&mut self, i: &'a ast::Item) {
+        if let Some(attr) = attr::find_by_name(&i.attrs, sym::rustc_test_marker) {
+            self.sess.parse_sess.buffer_lint(
+                UNNAMEABLE_TEST_ITEMS,
+                attr.span,
+                i.id,
+                crate::fluent_generated::builtin_macros_unnameable_test_items,
+            );
+        }
+    }
+}
+
 // Beware, this is duplicated in librustc_passes/entry.rs (with
 // `rustc_hir::Item`), so make sure to keep them in sync.
 fn entry_point_type(item: &ast::Item, depth: usize) -> EntryPointType {
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 67ea20112fe..3081dcfa2b7 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -477,7 +477,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
 
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
-        if let layout::LayoutError::SizeOverflow(_) = err {
+        if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
             self.0.sess.span_fatal(span, err.to_string())
         } else {
             span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 08507e19652..88dcafa7370 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -476,7 +476,7 @@ impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
 
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
-        if let LayoutError::SizeOverflow(_) = err {
+        if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
             self.sess().emit_fatal(respan(span, err.into_diagnostic()))
         } else {
             span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index cb093996d1d..3577fb2d951 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -985,7 +985,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
 
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
-        if let LayoutError::SizeOverflow(_) = err {
+        if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
             self.sess().emit_fatal(Spanned { span, node: err.into_diagnostic() })
         } else {
             span_bug!(span, "failed to get layout for `{ty}`: {err:?}")
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 32e71c6a641..2be7bce115d 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -61,9 +61,6 @@ fn uncached_llvm_type<'a, 'tcx>(
             }
             Some(name)
         }
-        // Use identified structure types for ADT. Due to pointee types in LLVM IR their definition
-        // might be recursive. Other cases are non-recursive and we can use literal structure types.
-        ty::Adt(..) => Some(String::new()),
         _ => None,
     };
 
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs
index 18268622341..ebf04e7a399 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs
@@ -1,6 +1,7 @@
 use pathdiff::diff_paths;
 use rustc_data_structures::fx::FxHashSet;
 use std::env;
+use std::ffi::OsString;
 use std::fs;
 use std::path::{Path, PathBuf};
 
@@ -12,7 +13,7 @@ pub struct RPathConfig<'a> {
     pub linker_is_gnu: bool,
 }
 
-pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
+pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<OsString> {
     // No rpath on windows
     if !config.has_rpath {
         return Vec::new();
@@ -21,36 +22,38 @@ pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
     debug!("preparing the RPATH!");
 
     let rpaths = get_rpaths(config);
-    let mut flags = rpaths_to_flags(&rpaths);
+    let mut flags = rpaths_to_flags(rpaths);
 
     if config.linker_is_gnu {
         // Use DT_RUNPATH instead of DT_RPATH if available
-        flags.push("-Wl,--enable-new-dtags".to_owned());
+        flags.push("-Wl,--enable-new-dtags".into());
 
         // Set DF_ORIGIN for substitute $ORIGIN
-        flags.push("-Wl,-z,origin".to_owned());
+        flags.push("-Wl,-z,origin".into());
     }
 
     flags
 }
 
-fn rpaths_to_flags(rpaths: &[String]) -> Vec<String> {
+fn rpaths_to_flags(rpaths: Vec<OsString>) -> Vec<OsString> {
     let mut ret = Vec::with_capacity(rpaths.len()); // the minimum needed capacity
 
     for rpath in rpaths {
-        if rpath.contains(',') {
+        if rpath.to_string_lossy().contains(',') {
             ret.push("-Wl,-rpath".into());
             ret.push("-Xlinker".into());
-            ret.push(rpath.clone());
+            ret.push(rpath);
         } else {
-            ret.push(format!("-Wl,-rpath,{}", &(*rpath)));
+            let mut single_arg = OsString::from("-Wl,-rpath,");
+            single_arg.push(rpath);
+            ret.push(single_arg);
         }
     }
 
     ret
 }
 
-fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec<String> {
+fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec<OsString> {
     debug!("output: {:?}", config.out_filename.display());
     debug!("libs:");
     for libpath in config.libs {
@@ -64,18 +67,18 @@ fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec<String> {
 
     debug!("rpaths:");
     for rpath in &rpaths {
-        debug!("    {}", rpath);
+        debug!("    {:?}", rpath);
     }
 
     // Remove duplicates
     minimize_rpaths(&rpaths)
 }
 
-fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>) -> Vec<String> {
+fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>) -> Vec<OsString> {
     config.libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect()
 }
 
-fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> String {
+fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> OsString {
     // Mac doesn't appear to support $ORIGIN
     let prefix = if config.is_like_osx { "@loader_path" } else { "$ORIGIN" };
 
@@ -87,8 +90,11 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> Str
     let output = fs::canonicalize(&output).unwrap_or(output);
     let relative = path_relative_from(&lib, &output)
         .unwrap_or_else(|| panic!("couldn't create relative path from {output:?} to {lib:?}"));
-    // FIXME (#9639): This needs to handle non-utf8 paths
-    format!("{}/{}", prefix, relative.to_str().expect("non-utf8 component in path"))
+
+    let mut rpath = OsString::from(prefix);
+    rpath.push("/");
+    rpath.push(relative);
+    rpath
 }
 
 // This routine is adapted from the *old* Path's `path_relative_from`
@@ -99,7 +105,7 @@ fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
     diff_paths(path, base)
 }
 
-fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
+fn minimize_rpaths(rpaths: &[OsString]) -> Vec<OsString> {
     let mut set = FxHashSet::default();
     let mut minimized = Vec::new();
     for rpath in rpaths {
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
index 604f19144a6..ac2e54072c4 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
@@ -1,32 +1,33 @@
 use super::RPathConfig;
 use super::{get_rpath_relative_to_output, minimize_rpaths, rpaths_to_flags};
+use std::ffi::OsString;
 use std::path::{Path, PathBuf};
 
 #[test]
 fn test_rpaths_to_flags() {
-    let flags = rpaths_to_flags(&["path1".to_string(), "path2".to_string()]);
+    let flags = rpaths_to_flags(vec!["path1".into(), "path2".into()]);
     assert_eq!(flags, ["-Wl,-rpath,path1", "-Wl,-rpath,path2"]);
 }
 
 #[test]
 fn test_minimize1() {
-    let res = minimize_rpaths(&["rpath1".to_string(), "rpath2".to_string(), "rpath1".to_string()]);
+    let res = minimize_rpaths(&["rpath1".into(), "rpath2".into(), "rpath1".into()]);
     assert!(res == ["rpath1", "rpath2",]);
 }
 
 #[test]
 fn test_minimize2() {
     let res = minimize_rpaths(&[
-        "1a".to_string(),
-        "2".to_string(),
-        "2".to_string(),
-        "1a".to_string(),
-        "4a".to_string(),
-        "1a".to_string(),
-        "2".to_string(),
-        "3".to_string(),
-        "4a".to_string(),
-        "3".to_string(),
+        "1a".into(),
+        "2".into(),
+        "2".into(),
+        "1a".into(),
+        "4a".into(),
+        "1a".into(),
+        "2".into(),
+        "3".into(),
+        "4a".into(),
+        "3".into(),
     ]);
     assert!(res == ["1a", "2", "4a", "3",]);
 }
@@ -58,15 +59,15 @@ fn test_rpath_relative() {
 
 #[test]
 fn test_xlinker() {
-    let args = rpaths_to_flags(&["a/normal/path".to_string(), "a,comma,path".to_string()]);
+    let args = rpaths_to_flags(vec!["a/normal/path".into(), "a,comma,path".into()]);
 
     assert_eq!(
         args,
         vec![
-            "-Wl,-rpath,a/normal/path".to_string(),
-            "-Wl,-rpath".to_string(),
-            "-Xlinker".to_string(),
-            "a,comma,path".to_string()
+            OsString::from("-Wl,-rpath,a/normal/path"),
+            OsString::from("-Wl,-rpath"),
+            OsString::from("-Xlinker"),
+            OsString::from("a,comma,path")
         ]
     );
 }
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 92792ab6477..f6936c80b77 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -215,14 +215,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             }
             sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
             sym::track_caller => {
-                if !tcx.is_closure(did.to_def_id())
+                let is_closure = tcx.is_closure(did.to_def_id());
+
+                if !is_closure
                     && let Some(fn_sig) = fn_sig()
                     && fn_sig.skip_binder().abi() != abi::Abi::Rust
                 {
                     struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
                         .emit();
                 }
-                if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
+                if is_closure
+                    && !tcx.features().closure_track_caller
+                    && !attr.span.allows_unstable(sym::closure_track_caller)
+                {
                     feature_err(
                         &tcx.sess.parse_sess,
                         sym::closure_track_caller,
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 5f4f5434b18..2dc856528f5 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -157,7 +157,6 @@ impl<Prov: Provenance> MemPlace<Prov> {
     }
 
     /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space.
-    /// This is the inverse of `ref_to_mplace`.
     #[inline(always)]
     pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate<Prov> {
         match self.meta {
@@ -415,7 +414,7 @@ where
     }
 
     /// Take a value, which represents a (thin or wide) reference, and make it a place.
-    /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`.
+    /// Alignment is just based on the type. This is the inverse of `mplace_to_ref()`.
     ///
     /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not
     /// want to ever use the place for memory access!
@@ -438,6 +437,18 @@ where
         Ok(MPlaceTy::from_aligned_ptr_with_meta(ptr.to_pointer(self)?, layout, meta))
     }
 
+    /// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space.
+    /// `align` information is lost!
+    /// This is the inverse of `ref_to_mplace`.
+    pub fn mplace_to_ref(
+        &self,
+        mplace: &MPlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
+        let imm = mplace.to_ref(self);
+        let layout = self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, mplace.layout.ty))?;
+        Ok(ImmTy::from_immediate(imm, layout))
+    }
+
     /// Take an operand, representing a pointer, and dereference it to a place.
     /// Corresponds to the `*` operator in Rust.
     #[instrument(skip(self), level = "debug")]
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index bf33c5cca10..1bd21473182 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -852,10 +852,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let instance = ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
         let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
 
-        let arg = ImmTy::from_immediate(
-            place.to_ref(self),
-            self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, place.layout.ty))?,
-        );
+        let arg = self.mplace_to_ref(&place)?;
         let ret = MPlaceTy::fake_alloc_zst(self.layout_of(self.tcx.types.unit)?);
 
         self.eval_fn_call(
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index a5c3cb3f857..f77bd53e76c 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -35,7 +35,7 @@ elsa = "=1.7.1"
 itertools = "0.10.1"
 
 [dependencies.parking_lot]
-version = "0.11"
+version = "0.12"
 
 [target.'cfg(windows)'.dependencies.windows]
 version = "0.48.0"
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 8f8b9eaa274..d4532873854 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -27,9 +27,7 @@ use rustc_data_structures::profiling::{
 use rustc_data_structures::sync::SeqCst;
 use rustc_errors::registry::{InvalidErrorCode, Registry};
 use rustc_errors::{markdown, ColorConfig};
-use rustc_errors::{
-    DiagnosticMessage, ErrorGuaranteed, Handler, PResult, SubdiagnosticMessage, TerminalUrl,
-};
+use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, PResult, SubdiagnosticMessage};
 use rustc_feature::find_gated_cfg;
 use rustc_fluent_macro::fluent_messages;
 use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
@@ -1405,15 +1403,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info:
         rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
     let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
         rustc_errors::ColorConfig::Auto,
-        None,
-        None,
         fallback_bundle,
-        false,
-        false,
-        None,
-        false,
-        false,
-        TerminalUrl::No,
     ));
     let handler = rustc_errors::Handler::with_emitter(emitter);
 
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index e8bcd7c1184..faab9f09da8 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -25,6 +25,7 @@ annotate-snippets = "0.9"
 termize = "0.1.1"
 serde = { version = "1.0.125", features = [ "derive" ] }
 serde_json = "1.0.59"
+derive_setters = "0.1.6"
 
 [target.'cfg(windows)'.dependencies.windows]
 version = "0.48.0"
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 44654571d43..0cae06881b1 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -7,8 +7,6 @@
 //!
 //! The output types are defined in `rustc_session::config::ErrorOutputType`.
 
-use Destination::*;
-
 use rustc_span::source_map::SourceMap;
 use rustc_span::{FileLines, SourceFile, Span};
 
@@ -24,6 +22,7 @@ use crate::{
 };
 use rustc_lint_defs::pluralize;
 
+use derive_setters::Setters;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
 use rustc_error_messages::{FluentArgs, SpanLabel};
@@ -35,8 +34,8 @@ use std::io::prelude::*;
 use std::io::{self, IsTerminal};
 use std::iter;
 use std::path::Path;
-use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream};
-use termcolor::{Buffer, Color, WriteColor};
+use termcolor::{Ansi, Buffer, BufferWriter, ColorChoice, ColorSpec, StandardStream};
+use termcolor::{Color, WriteColor};
 
 /// Default column width, used in tests and when terminal dimensions cannot be determined.
 const DEFAULT_COLUMN_WIDTH: usize = 140;
@@ -60,31 +59,15 @@ impl HumanReadableErrorType {
     }
     pub fn new_emitter(
         self,
-        dst: Box<dyn Write + Send>,
-        source_map: Option<Lrc<SourceMap>>,
-        bundle: Option<Lrc<FluentBundle>>,
+        mut dst: Box<dyn WriteColor + Send>,
         fallback_bundle: LazyFallbackBundle,
-        teach: bool,
-        diagnostic_width: Option<usize>,
-        macro_backtrace: bool,
-        track_diagnostics: bool,
-        terminal_url: TerminalUrl,
     ) -> EmitterWriter {
         let (short, color_config) = self.unzip();
         let color = color_config.suggests_using_colors();
-        EmitterWriter::new(
-            dst,
-            source_map,
-            bundle,
-            fallback_bundle,
-            short,
-            teach,
-            color,
-            diagnostic_width,
-            macro_backtrace,
-            track_diagnostics,
-            terminal_url,
-        )
+        if !dst.supports_color() && color {
+            dst = Box::new(Ansi::new(dst));
+        }
+        EmitterWriter::new(dst, fallback_bundle).short_message(short)
     }
 }
 
@@ -639,10 +622,13 @@ impl ColorConfig {
 }
 
 /// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short`
+#[derive(Setters)]
 pub struct EmitterWriter {
+    #[setters(skip)]
     dst: Destination,
     sm: Option<Lrc<SourceMap>>,
     fluent_bundle: Option<Lrc<FluentBundle>>,
+    #[setters(skip)]
     fallback_bundle: LazyFallbackBundle,
     short_message: bool,
     teach: bool,
@@ -662,65 +648,32 @@ pub struct FileWithAnnotatedLines {
 }
 
 impl EmitterWriter {
-    pub fn stderr(
-        color_config: ColorConfig,
-        source_map: Option<Lrc<SourceMap>>,
-        fluent_bundle: Option<Lrc<FluentBundle>>,
-        fallback_bundle: LazyFallbackBundle,
-        short_message: bool,
-        teach: bool,
-        diagnostic_width: Option<usize>,
-        macro_backtrace: bool,
-        track_diagnostics: bool,
-        terminal_url: TerminalUrl,
-    ) -> EmitterWriter {
-        let dst = Destination::from_stderr(color_config);
+    pub fn stderr(color_config: ColorConfig, fallback_bundle: LazyFallbackBundle) -> EmitterWriter {
+        let dst = from_stderr(color_config);
+        Self::create(dst, fallback_bundle)
+    }
+
+    fn create(dst: Destination, fallback_bundle: LazyFallbackBundle) -> EmitterWriter {
         EmitterWriter {
             dst,
-            sm: source_map,
-            fluent_bundle,
+            sm: None,
+            fluent_bundle: None,
             fallback_bundle,
-            short_message,
-            teach,
+            short_message: false,
+            teach: false,
             ui_testing: false,
-            diagnostic_width,
-            macro_backtrace,
-            track_diagnostics,
-            terminal_url,
+            diagnostic_width: None,
+            macro_backtrace: false,
+            track_diagnostics: false,
+            terminal_url: TerminalUrl::No,
         }
     }
 
     pub fn new(
-        dst: Box<dyn Write + Send>,
-        source_map: Option<Lrc<SourceMap>>,
-        fluent_bundle: Option<Lrc<FluentBundle>>,
+        dst: Box<dyn WriteColor + Send>,
         fallback_bundle: LazyFallbackBundle,
-        short_message: bool,
-        teach: bool,
-        colored: bool,
-        diagnostic_width: Option<usize>,
-        macro_backtrace: bool,
-        track_diagnostics: bool,
-        terminal_url: TerminalUrl,
     ) -> EmitterWriter {
-        EmitterWriter {
-            dst: Raw(dst, colored),
-            sm: source_map,
-            fluent_bundle,
-            fallback_bundle,
-            short_message,
-            teach,
-            ui_testing: false,
-            diagnostic_width,
-            macro_backtrace,
-            track_diagnostics,
-            terminal_url,
-        }
-    }
-
-    pub fn ui_testing(mut self, ui_testing: bool) -> Self {
-        self.ui_testing = ui_testing;
-        self
+        Self::create(dst, fallback_bundle)
     }
 
     fn maybe_anonymized(&self, line_num: usize) -> Cow<'static, str> {
@@ -2203,11 +2156,10 @@ impl EmitterWriter {
             Err(e) => panic!("failed to emit error: {e}"),
         }
 
-        let mut dst = self.dst.writable();
-        match writeln!(dst) {
+        match writeln!(self.dst) {
             Err(e) => panic!("failed to emit error: {e}"),
             _ => {
-                if let Err(e) = dst.flush() {
+                if let Err(e) = self.dst.flush() {
                     panic!("failed to emit error: {e}")
                 }
             }
@@ -2618,8 +2570,6 @@ fn emit_to_destination(
 ) -> io::Result<()> {
     use crate::lock;
 
-    let mut dst = dst.writable();
-
     // In order to prevent error message interleaving, where multiple error lines get intermixed
     // when multiple compiler processes error simultaneously, we emit errors with additional
     // steps.
@@ -2635,7 +2585,8 @@ fn emit_to_destination(
     let _buffer_lock = lock::acquire_global_lock("rustc_errors");
     for (pos, line) in rendered_buffer.iter().enumerate() {
         for part in line {
-            dst.apply_style(*lvl, part.style)?;
+            let style = part.style.color_spec(*lvl);
+            dst.set_color(&style)?;
             write!(dst, "{}", part.text)?;
             dst.reset()?;
         }
@@ -2647,61 +2598,69 @@ fn emit_to_destination(
     Ok(())
 }
 
-pub enum Destination {
-    Terminal(StandardStream),
-    Buffered(BufferWriter),
-    // The bool denotes whether we should be emitting ansi color codes or not
-    Raw(Box<(dyn Write + Send)>, bool),
-}
+pub type Destination = Box<(dyn WriteColor + Send)>;
 
-pub enum WritableDst<'a> {
-    Terminal(&'a mut StandardStream),
-    Buffered(&'a mut BufferWriter, Buffer),
-    Raw(&'a mut (dyn Write + Send)),
-    ColoredRaw(Ansi<&'a mut (dyn Write + Send)>),
+struct Buffy {
+    buffer_writer: BufferWriter,
+    buffer: Buffer,
 }
 
-impl Destination {
-    fn from_stderr(color: ColorConfig) -> Destination {
-        let choice = color.to_color_choice();
-        // On Windows we'll be performing global synchronization on the entire
-        // system for emitting rustc errors, so there's no need to buffer
-        // anything.
-        //
-        // On non-Windows we rely on the atomicity of `write` to ensure errors
-        // don't get all jumbled up.
-        if cfg!(windows) {
-            Terminal(StandardStream::stderr(choice))
-        } else {
-            Buffered(BufferWriter::stderr(choice))
-        }
+impl Write for Buffy {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.buffer.write(buf)
     }
 
-    fn writable(&mut self) -> WritableDst<'_> {
-        match *self {
-            Destination::Terminal(ref mut t) => WritableDst::Terminal(t),
-            Destination::Buffered(ref mut t) => {
-                let buf = t.buffer();
-                WritableDst::Buffered(t, buf)
-            }
-            Destination::Raw(ref mut t, false) => WritableDst::Raw(t),
-            Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)),
+    fn flush(&mut self) -> io::Result<()> {
+        self.buffer_writer.print(&self.buffer)?;
+        self.buffer.clear();
+        Ok(())
+    }
+}
+
+impl Drop for Buffy {
+    fn drop(&mut self) {
+        if !self.buffer.is_empty() {
+            self.flush().unwrap();
+            panic!("buffers need to be flushed in order to print their contents");
         }
     }
+}
 
+impl WriteColor for Buffy {
     fn supports_color(&self) -> bool {
-        match *self {
-            Self::Terminal(ref stream) => stream.supports_color(),
-            Self::Buffered(ref buffer) => buffer.buffer().supports_color(),
-            Self::Raw(_, supports_color) => supports_color,
-        }
+        self.buffer.supports_color()
+    }
+
+    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
+        self.buffer.set_color(spec)
+    }
+
+    fn reset(&mut self) -> io::Result<()> {
+        self.buffer.reset()
+    }
+}
+
+fn from_stderr(color: ColorConfig) -> Destination {
+    let choice = color.to_color_choice();
+    // On Windows we'll be performing global synchronization on the entire
+    // system for emitting rustc errors, so there's no need to buffer
+    // anything.
+    //
+    // On non-Windows we rely on the atomicity of `write` to ensure errors
+    // don't get all jumbled up.
+    if cfg!(windows) {
+        Box::new(StandardStream::stderr(choice))
+    } else {
+        let buffer_writer = BufferWriter::stderr(choice);
+        let buffer = buffer_writer.buffer();
+        Box::new(Buffy { buffer_writer, buffer })
     }
 }
 
-impl<'a> WritableDst<'a> {
-    fn apply_style(&mut self, lvl: Level, style: Style) -> io::Result<()> {
+impl Style {
+    fn color_spec(&self, lvl: Level) -> ColorSpec {
         let mut spec = ColorSpec::new();
-        match style {
+        match self {
             Style::Addition => {
                 spec.set_fg(Some(Color::Green)).set_intense(true);
             }
@@ -2746,53 +2705,7 @@ impl<'a> WritableDst<'a> {
                 spec.set_bold(true);
             }
         }
-        self.set_color(&spec)
-    }
-
-    fn set_color(&mut self, color: &ColorSpec) -> io::Result<()> {
-        match *self {
-            WritableDst::Terminal(ref mut t) => t.set_color(color),
-            WritableDst::Buffered(_, ref mut t) => t.set_color(color),
-            WritableDst::ColoredRaw(ref mut t) => t.set_color(color),
-            WritableDst::Raw(_) => Ok(()),
-        }
-    }
-
-    fn reset(&mut self) -> io::Result<()> {
-        match *self {
-            WritableDst::Terminal(ref mut t) => t.reset(),
-            WritableDst::Buffered(_, ref mut t) => t.reset(),
-            WritableDst::ColoredRaw(ref mut t) => t.reset(),
-            WritableDst::Raw(_) => Ok(()),
-        }
-    }
-}
-
-impl<'a> Write for WritableDst<'a> {
-    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
-        match *self {
-            WritableDst::Terminal(ref mut t) => t.write(bytes),
-            WritableDst::Buffered(_, ref mut buf) => buf.write(bytes),
-            WritableDst::Raw(ref mut w) => w.write(bytes),
-            WritableDst::ColoredRaw(ref mut t) => t.write(bytes),
-        }
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        match *self {
-            WritableDst::Terminal(ref mut t) => t.flush(),
-            WritableDst::Buffered(_, ref mut buf) => buf.flush(),
-            WritableDst::Raw(ref mut w) => w.flush(),
-            WritableDst::ColoredRaw(ref mut w) => w.flush(),
-        }
-    }
-}
-
-impl<'a> Drop for WritableDst<'a> {
-    fn drop(&mut self) {
-        if let WritableDst::Buffered(ref mut dst, ref mut buf) = self {
-            drop(dst.print(buf));
-        }
+        spec
     }
 }
 
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 55f7c485024..b8f58e3057c 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -10,6 +10,7 @@
 // FIXME: spec the JSON output properly.
 
 use rustc_span::source_map::{FilePathMapping, SourceMap};
+use termcolor::{ColorSpec, WriteColor};
 
 use crate::emitter::{Emitter, HumanReadableErrorType};
 use crate::registry::Registry;
@@ -356,20 +357,29 @@ impl Diagnostic {
                 self.0.lock().unwrap().flush()
             }
         }
+        impl WriteColor for BufWriter {
+            fn supports_color(&self) -> bool {
+                false
+            }
+
+            fn set_color(&mut self, _spec: &ColorSpec) -> io::Result<()> {
+                Ok(())
+            }
+
+            fn reset(&mut self) -> io::Result<()> {
+                Ok(())
+            }
+        }
         let buf = BufWriter::default();
         let output = buf.clone();
         je.json_rendered
-            .new_emitter(
-                Box::new(buf),
-                Some(je.sm.clone()),
-                je.fluent_bundle.clone(),
-                je.fallback_bundle.clone(),
-                false,
-                je.diagnostic_width,
-                je.macro_backtrace,
-                je.track_diagnostics,
-                je.terminal_url,
-            )
+            .new_emitter(Box::new(buf), je.fallback_bundle.clone())
+            .sm(Some(je.sm.clone()))
+            .fluent_bundle(je.fluent_bundle.clone())
+            .diagnostic_width(je.diagnostic_width)
+            .macro_backtrace(je.macro_backtrace)
+            .track_diagnostics(je.track_diagnostics)
+            .terminal_url(je.terminal_url)
             .ui_testing(je.ui_testing)
             .emit_diagnostic(diag);
         let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 3b753629128..7d660d2dbaa 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -557,18 +557,7 @@ impl Handler {
         sm: Option<Lrc<SourceMap>>,
         fallback_bundle: LazyFallbackBundle,
     ) -> Self {
-        let emitter = Box::new(EmitterWriter::stderr(
-            ColorConfig::Auto,
-            sm,
-            None,
-            fallback_bundle,
-            false,
-            false,
-            None,
-            false,
-            false,
-            TerminalUrl::No,
-        ));
+        let emitter = Box::new(EmitterWriter::stderr(ColorConfig::Auto, fallback_bundle).sm(sm));
         Self::with_emitter(emitter)
     }
     pub fn disable_warnings(mut self) -> Self {
diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml
index 2dae0e3f53c..02da5b5dc53 100644
--- a/compiler/rustc_expand/Cargo.toml
+++ b/compiler/rustc_expand/Cargo.toml
@@ -27,3 +27,4 @@ rustc_span = { path = "../rustc_span" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 thin-vec = "0.2.12"
 tracing = "0.1"
+termcolor = "1.2"
diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs
index 30fa5fea407..8e3219c138c 100644
--- a/compiler/rustc_expand/src/tests.rs
+++ b/compiler/rustc_expand/src/tests.rs
@@ -8,7 +8,8 @@ use rustc_span::{BytePos, Span};
 
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::{Handler, MultiSpan, PResult, TerminalUrl};
+use rustc_errors::{Handler, MultiSpan, PResult};
+use termcolor::WriteColor;
 
 use std::io;
 use std::io::prelude::*;
@@ -29,19 +30,9 @@ fn create_test_handler() -> (Handler, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
         vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
         false,
     );
-    let emitter = EmitterWriter::new(
-        Box::new(Shared { data: output.clone() }),
-        Some(source_map.clone()),
-        None,
-        fallback_bundle,
-        false,
-        false,
-        false,
-        Some(140),
-        false,
-        false,
-        TerminalUrl::No,
-    );
+    let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), fallback_bundle)
+        .sm(Some(source_map.clone()))
+        .diagnostic_width(Some(140));
     let handler = Handler::with_emitter(Box::new(emitter));
     (handler, source_map, output)
 }
@@ -165,6 +156,20 @@ pub(crate) struct Shared<T: Write> {
     pub data: Arc<Mutex<T>>,
 }
 
+impl<T: Write> WriteColor for Shared<T> {
+    fn supports_color(&self) -> bool {
+        false
+    }
+
+    fn set_color(&mut self, _spec: &termcolor::ColorSpec) -> io::Result<()> {
+        Ok(())
+    }
+
+    fn reset(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
 impl<T: Write> Write for Shared<T> {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         self.data.lock().unwrap().write(buf)
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index ff25f744ded..2a0dab64af5 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -339,6 +339,8 @@ declare_features! (
     (active, async_closure, "1.37.0", Some(62290), None),
     /// Allows async functions to be declared, implemented, and used in traits.
     (active, async_fn_in_trait, "1.66.0", Some(91611), None),
+    /// Allows `#[track_caller]` on async functions.
+    (active, async_fn_track_caller, "CURRENT_RUSTC_VERSION", Some(110011), None),
     /// Allows builtin # foo() syntax
     (active, builtin_syntax, "1.71.0", Some(110680), None),
     /// Allows `c"foo"` literals.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 6b76e16825f..bc05565fed4 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1754,7 +1754,7 @@ impl Expr<'_> {
 
             ExprKind::Unary(UnOp::Deref, _) => true,
 
-            ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _) => {
+            ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => {
                 allow_projections_from(base) || base.is_place_expr(allow_projections_from)
             }
 
@@ -1831,7 +1831,7 @@ impl Expr<'_> {
             ExprKind::Type(base, _)
             | ExprKind::Unary(_, base)
             | ExprKind::Field(base, _)
-            | ExprKind::Index(base, _)
+            | ExprKind::Index(base, _, _)
             | ExprKind::AddrOf(.., base)
             | ExprKind::Cast(base, _) => {
                 // This isn't exactly true for `Index` and all `Unary`, but we are using this
@@ -2015,7 +2015,9 @@ pub enum ExprKind<'hir> {
     /// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct or tuple field.
     Field(&'hir Expr<'hir>, Ident),
     /// An indexing operation (`foo[2]`).
-    Index(&'hir Expr<'hir>, &'hir Expr<'hir>),
+    /// Similar to [`ExprKind::MethodCall`], the final `Span` represents the span of the brackets
+    /// and index.
+    Index(&'hir Expr<'hir>, &'hir Expr<'hir>, Span),
 
     /// Path to a definition, possibly containing lifetime or type parameters.
     Path(QPath<'hir>),
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index a8a94e6a476..9d1d899eef0 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -780,7 +780,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             visitor.visit_expr(subexpression);
             visitor.visit_ident(ident);
         }
-        ExprKind::Index(ref main_expression, ref index_expression) => {
+        ExprKind::Index(ref main_expression, ref index_expression, _) => {
             visitor.visit_expr(main_expression);
             visitor.visit_expr(index_expression)
         }
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index e64848da86b..16d4d099c7e 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -245,13 +245,14 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
         }
         // `ForeignItem`s are handled separately.
         hir::ItemKind::ForeignMod { .. } => {}
-        hir::ItemKind::TyAlias(hir_ty, ..) => {
+        hir::ItemKind::TyAlias(hir_ty, ast_generics) => {
             if tcx.features().lazy_type_alias
                 || tcx.type_of(item.owner_id).skip_binder().has_opaque_types()
             {
                 // Bounds of lazy type aliases and of eager ones that contain opaque types are respected.
                 // E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`.
                 check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
+                check_variances_for_type_defn(tcx, item, ast_generics);
             }
         }
         _ => {}
@@ -1700,10 +1701,27 @@ fn check_variances_for_type_defn<'tcx>(
     hir_generics: &hir::Generics<'_>,
 ) {
     let identity_args = ty::GenericArgs::identity_for_item(tcx, item.owner_id);
-    for field in tcx.adt_def(item.owner_id).all_fields() {
-        if field.ty(tcx, identity_args).references_error() {
-            return;
+
+    match item.kind {
+        ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
+            for field in tcx.adt_def(item.owner_id).all_fields() {
+                if field.ty(tcx, identity_args).references_error() {
+                    return;
+                }
+            }
+        }
+        ItemKind::TyAlias(..) => {
+            let ty = tcx.type_of(item.owner_id).instantiate_identity();
+
+            if tcx.features().lazy_type_alias || ty.has_opaque_types() {
+                if ty.references_error() {
+                    return;
+                }
+            } else {
+                bug!();
+            }
         }
+        _ => bug!(),
     }
 
     let ty_predicates = tcx.predicates_of(item.owner_id);
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index ec8889781f4..4a3d522e488 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -6,7 +6,7 @@
 use hir::def_id::{DefId, LocalDefId};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
 
 use super::terms::VarianceTerm::*;
@@ -78,6 +78,12 @@ pub fn add_constraints_from_crate<'a, 'tcx>(
                 }
             }
             DefKind::Fn | DefKind::AssocFn => constraint_cx.build_constraints_for_item(def_id),
+            DefKind::TyAlias
+                if tcx.features().lazy_type_alias
+                    || tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
+            {
+                constraint_cx.build_constraints_for_item(def_id)
+            }
             _ => {}
         }
     }
@@ -101,7 +107,18 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
 
         let inferred_start = self.terms_cx.inferred_starts[&def_id];
         let current_item = &CurrentItem { inferred_start };
-        match tcx.type_of(def_id).instantiate_identity().kind() {
+        let ty = tcx.type_of(def_id).instantiate_identity();
+
+        // The type as returned by `type_of` is the underlying type and generally not a weak projection.
+        // Therefore we need to check the `DefKind` first.
+        if let DefKind::TyAlias = tcx.def_kind(def_id)
+            && (tcx.features().lazy_type_alias || ty.has_opaque_types())
+        {
+            self.add_constraints_from_ty(current_item, ty, self.covariant);
+            return;
+        }
+
+        match ty.kind() {
             ty::Adt(def, _) => {
                 // Not entirely obvious: constraints on structs/enums do not
                 // affect the variance of their type parameters. See discussion
@@ -127,6 +144,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             }
 
             ty::Error(_) => {}
+
             _ => {
                 span_bug!(
                     tcx.def_span(def_id),
@@ -252,10 +270,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.add_constraints_from_args(current, def.did(), args, variance);
             }
 
-            ty::Alias(_, ref data) => {
+            ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, ref data) => {
                 self.add_constraints_from_invariant_args(current, data.args, variance);
             }
 
+            ty::Alias(ty::Weak, ref data) => {
+                self.add_constraints_from_args(current, data.def_id, data.args, variance);
+            }
+
             ty::Dynamic(data, r, _) => {
                 // The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
                 self.add_constraints_from_region(current, r, variance);
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 6952a3fa66f..2ef294c6793 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -8,7 +8,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, CrateVariancesMap, GenericArgsRef, Ty, TyCtxt};
-use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable};
+use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
 use std::ops::ControlFlow;
 
 /// Defines the `TermsContext` basically houses an arena where we can
@@ -56,6 +56,14 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
             let crate_map = tcx.crate_variances(());
             return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
         }
+        DefKind::TyAlias
+            if tcx.features().lazy_type_alias
+                || tcx.type_of(item_def_id).instantiate_identity().has_opaque_types() =>
+        {
+            // These are inferred.
+            let crate_map = tcx.crate_variances(());
+            return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
+        }
         DefKind::OpaqueTy => {
             return variance_of_opaque(tcx, item_def_id);
         }
diff --git a/compiler/rustc_hir_analysis/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs
index ed03c5da26f..1ef3d383bd8 100644
--- a/compiler/rustc_hir_analysis/src/variance/terms.rs
+++ b/compiler/rustc_hir_analysis/src/variance/terms.rs
@@ -12,7 +12,7 @@
 use rustc_arena::DroplessArena;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use std::fmt;
 
 use self::VarianceTerm::*;
@@ -97,6 +97,12 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(
                 }
             }
             DefKind::Fn | DefKind::AssocFn => terms_cx.add_inferreds_for_item(def_id),
+            DefKind::TyAlias
+                if tcx.features().lazy_type_alias
+                    || tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
+            {
+                terms_cx.add_inferreds_for_item(def_id)
+            }
             _ => {}
         }
     }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 2d8b956771b..fda46798708 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1526,7 +1526,7 @@ impl<'a> State<'a> {
                 self.word(".");
                 self.print_ident(ident);
             }
-            hir::ExprKind::Index(expr, index) => {
+            hir::ExprKind::Index(expr, index, _) => {
                 self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
                 self.word("[");
                 self.print_expr(index);
@@ -2419,7 +2419,7 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool {
         | hir::ExprKind::Cast(x, _)
         | hir::ExprKind::Type(x, _)
         | hir::ExprKind::Field(x, _)
-        | hir::ExprKind::Index(x, _) => {
+        | hir::ExprKind::Index(x, _, _) => {
             // `&X { y: 1 }, X { y: 1 }.y`
             contains_exterior_struct_lit(x)
         }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 80d7cc57edb..2af8648455b 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -345,7 +345,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.check_expr_struct(expr, expected, qpath, fields, base_expr)
             }
             ExprKind::Field(base, field) => self.check_field(expr, &base, field, expected),
-            ExprKind::Index(base, idx) => self.check_expr_index(base, idx, expr),
+            ExprKind::Index(base, idx, brackets_span) => {
+                self.check_expr_index(base, idx, expr, brackets_span)
+            }
             ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src),
             hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar),
         }
@@ -2840,6 +2842,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         base: &'tcx hir::Expr<'tcx>,
         idx: &'tcx hir::Expr<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
+        brackets_span: Span,
     ) -> Ty<'tcx> {
         let base_t = self.check_expr(&base);
         let idx_t = self.check_expr(&idx);
@@ -2873,7 +2876,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                     let mut err = type_error_struct!(
                         self.tcx.sess,
-                        expr.span,
+                        brackets_span,
                         base_t,
                         E0608,
                         "cannot index into a value of type `{base_t}`",
@@ -2887,16 +2890,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node
                             && i < types.len().try_into().expect("expected tuple index to be < usize length")
                         {
-                            let snip = self.tcx.sess.source_map().span_to_snippet(base.span);
-                            if let Ok(snip) = snip {
-                                err.span_suggestion(
-                                    expr.span,
-                                    "to access tuple elements, use",
-                                    format!("{snip}.{i}"),
-                                    Applicability::MachineApplicable,
-                                );
-                                needs_note = false;
-                            }
+
+                            err.span_suggestion(
+                                brackets_span,
+                                "to access tuple elements, use",
+                                format!(".{i}"),
+                                Applicability::MachineApplicable,
+                            );
+                            needs_note = false;
                         } else if let ExprKind::Path(..) = idx.peel_borrows().kind {
                             err.span_label(idx.span, "cannot access tuple elements at a variable index");
                         }
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index a59061cbf67..840910732d8 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -211,7 +211,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                 self.select_from_expr(base);
             }
 
-            hir::ExprKind::Index(lhs, rhs) => {
+            hir::ExprKind::Index(lhs, rhs, _) => {
                 // lhs[rhs]
                 self.select_from_expr(lhs);
                 self.consume_expr(rhs);
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index d4edd08d302..89bbb4c2203 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1620,8 +1620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     .iter()
                                     .enumerate()
                                     .filter(|x| x.1.hir_id == *hir_id)
-                                    .map(|(i, _)| init_tup.get(i).unwrap())
-                                    .next()
+                                    .find_map(|(i, _)| init_tup.get(i))
                                 {
                                     self.note_type_is_not_clone_inner_expr(init)
                                 } else {
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 0700e2e0554..4ea53c7eaae 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -198,13 +198,14 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     }
 
     /// Like `pat_ty`, but ignores implicit `&` patterns.
+    #[instrument(level = "debug", skip(self), ret)]
     fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
         let base_ty = self.node_ty(pat.hir_id)?;
-        debug!("pat_ty(pat={:?}) base_ty={:?}", pat, base_ty);
+        trace!(?base_ty);
 
         // This code detects whether we are looking at a `ref x`,
         // and if so, figures out what the type *being borrowed* is.
-        let ret_ty = match pat.kind {
+        match pat.kind {
             PatKind::Binding(..) => {
                 let bm = *self
                     .typeck_results
@@ -217,21 +218,18 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
                     // but what we want here is the type of the underlying value being borrowed.
                     // So peel off one-level, turning the &T into T.
                     match base_ty.builtin_deref(false) {
-                        Some(t) => t.ty,
+                        Some(t) => Ok(t.ty),
                         None => {
-                            debug!("By-ref binding of non-derefable type {:?}", base_ty);
-                            return Err(());
+                            debug!("By-ref binding of non-derefable type");
+                            Err(())
                         }
                     }
                 } else {
-                    base_ty
+                    Ok(base_ty)
                 }
             }
-            _ => base_ty,
-        };
-        debug!("pat_ty(pat={:?}) ret_ty={:?}", pat, ret_ty);
-
-        Ok(ret_ty)
+            _ => Ok(base_ty),
+        }
     }
 
     pub(crate) fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
@@ -299,13 +297,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         }
     }
 
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     pub(crate) fn cat_expr_unadjusted(
         &self,
         expr: &hir::Expr<'_>,
     ) -> McResult<PlaceWithHirId<'tcx>> {
-        debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr);
-
         let expr_ty = self.expr_ty(expr)?;
         match expr.kind {
             hir::ExprKind::Unary(hir::UnOp::Deref, ref e_base) => {
@@ -319,7 +315,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
 
             hir::ExprKind::Field(ref base, _) => {
                 let base = self.cat_expr(base)?;
-                debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base);
+                debug!(?base);
 
                 let field_idx = self
                     .typeck_results
@@ -336,7 +332,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
                 ))
             }
 
-            hir::ExprKind::Index(ref base, _) => {
+            hir::ExprKind::Index(ref base, _, _) => {
                 if self.typeck_results.is_method_call(expr) {
                     // If this is an index implemented by a method call, then it
                     // will include an implicit deref of the result.
@@ -389,7 +385,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         }
     }
 
-    #[instrument(level = "debug", skip(self, span))]
+    #[instrument(level = "debug", skip(self, span), ret)]
     pub(crate) fn cat_res(
         &self,
         hir_id: hir::HirId,
@@ -430,6 +426,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     /// Note: the actual upvar access contains invisible derefs of closure
     /// environment and upvar reference as appropriate. Only regionck cares
     /// about these dereferences, so we let it compute them as needed.
+    #[instrument(level = "debug", skip(self), ret)]
     fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult<PlaceWithHirId<'tcx>> {
         let closure_expr_def_id = self.body_owner;
 
@@ -439,24 +436,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         };
         let var_ty = self.node_ty(var_id)?;
 
-        let ret = PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new());
-
-        debug!("cat_upvar ret={:?}", ret);
-        Ok(ret)
+        Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()))
     }
 
+    #[instrument(level = "debug", skip(self), ret)]
     pub(crate) fn cat_rvalue(
         &self,
         hir_id: hir::HirId,
         span: Span,
         expr_ty: Ty<'tcx>,
     ) -> PlaceWithHirId<'tcx> {
-        debug!("cat_rvalue hir_id={:?}, expr_ty={:?}, span={:?}", hir_id, expr_ty, span);
-        let ret = PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new());
-        debug!("cat_rvalue ret={:?}", ret);
-        ret
+        PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new())
     }
 
+    #[instrument(level = "debug", skip(self, node), ret)]
     pub(crate) fn cat_projection<N: HirNode>(
         &self,
         node: &N,
@@ -464,16 +457,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         ty: Ty<'tcx>,
         kind: ProjectionKind,
     ) -> PlaceWithHirId<'tcx> {
+        let place_ty = base_place.place.ty();
         let mut projections = base_place.place.projections;
+
+        let node_ty = self.typeck_results.node_type(node.hir_id());
+        // Opaque types can't have field projections, but we can instead convert
+        // the current place in-place (heh) to the hidden type, and then apply all
+        // follow up projections on that.
+        if node_ty != place_ty && place_ty.has_opaque_types() {
+            projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
+        }
         projections.push(Projection { kind, ty });
-        let ret = PlaceWithHirId::new(
+        PlaceWithHirId::new(
             node.hir_id(),
             base_place.place.base_ty,
             base_place.place.base,
             projections,
-        );
-        debug!("cat_field ret {:?}", ret);
-        ret
+        )
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -497,7 +497,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         self.cat_deref(expr, base)
     }
 
-    #[instrument(level = "debug", skip(self, node))]
+    #[instrument(level = "debug", skip(self, node), ret)]
     fn cat_deref(
         &self,
         node: &impl HirNode,
@@ -514,14 +514,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         let mut projections = base_place.place.projections;
         projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty });
 
-        let ret = PlaceWithHirId::new(
+        Ok(PlaceWithHirId::new(
             node.hir_id(),
             base_place.place.base_ty,
             base_place.place.base,
             projections,
-        );
-        debug!("cat_deref ret {:?}", ret);
-        Ok(ret)
+        ))
     }
 
     pub(crate) fn cat_pattern<F>(
@@ -603,6 +601,13 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         }
     }
 
+    /// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
+    /// is being matched against.
+    ///
+    /// In general, the way that this works is that we walk down the pattern,
+    /// constructing a `PlaceWithHirId` that represents the path that will be taken
+    /// to reach the value being matched.
+    #[instrument(skip(self, op), ret, level = "debug")]
     fn cat_pattern_<F>(
         &self,
         mut place_with_id: PlaceWithHirId<'tcx>,
@@ -612,15 +617,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     where
         F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
     {
-        // Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
-        // is being matched against.
-        //
-        // In general, the way that this works is that we walk down the pattern,
-        // constructing a `PlaceWithHirId` that represents the path that will be taken
-        // to reach the value being matched.
-
-        debug!("cat_pattern(pat={:?}, place_with_id={:?})", pat, place_with_id);
-
         // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly.
         // `PlaceWithHirId`s are constructed differently from patterns. For example, in
         //
@@ -654,11 +650,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
         // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
         for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) {
-            debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id);
+            debug!("applying adjustment to place_with_id={:?}", place_with_id);
             place_with_id = self.cat_deref(pat, place_with_id)?;
         }
         let place_with_id = place_with_id; // lose mutability
-        debug!("cat_pattern: applied adjustment derefs to get place_with_id={:?}", place_with_id);
+        debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id);
 
         // Invoke the callback, but only now, after the `place_with_id` has adjusted.
         //
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index 1eb84eb1637..406434e09e6 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -284,7 +284,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut exprs = vec![expr];
 
         while let hir::ExprKind::Field(ref expr, _)
-        | hir::ExprKind::Index(ref expr, _)
+        | hir::ExprKind::Index(ref expr, _, _)
         | hir::ExprKind::Unary(hir::UnOp::Deref, ref expr) = exprs.last().unwrap().kind
         {
             exprs.push(expr);
diff --git a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
index 091e88abe97..04d84102336 100644
--- a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
+++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
@@ -40,7 +40,7 @@ fn record_rvalue_scope_rec(
             hir::ExprKind::AddrOf(_, _, subexpr)
             | hir::ExprKind::Unary(hir::UnOp::Deref, subexpr)
             | hir::ExprKind::Field(subexpr, _)
-            | hir::ExprKind::Index(subexpr, _) => {
+            | hir::ExprKind::Index(subexpr, _, _) => {
                 expr = subexpr;
             }
             _ => {
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index be939560c45..1a41786d251 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -264,12 +264,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.demand_eqtype(span, closure_kind.to_ty(self.tcx), closure_kind_ty);
 
             // If we have an origin, store it.
-            if let Some(origin) = origin {
-                let origin = if enable_precise_capture(span) {
-                    (origin.0, origin.1)
-                } else {
-                    (origin.0, Place { projections: vec![], ..origin.1 })
-                };
+            if let Some(mut origin) = origin {
+                if !enable_precise_capture(span) {
+                    // Without precise captures, we just capture the base and ignore
+                    // the projections.
+                    origin.1.projections.clear()
+                }
 
                 self.typeck_results
                     .borrow_mut()
@@ -294,10 +294,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Equate the type variables for the upvars with the actual types.
         let final_upvar_tys = self.final_upvar_tys(closure_def_id);
-        debug!(
-            "analyze_closure: id={:?} args={:?} final_upvar_tys={:?}",
-            closure_hir_id, args, final_upvar_tys
-        );
+        debug!(?closure_hir_id, ?args, ?final_upvar_tys);
 
         // Build a tuple (U0..Un) of the final upvar types U0..Un
         // and unify the upvar tuple type in the closure with it:
@@ -338,10 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let upvar_ty = captured_place.place.ty();
                 let capture = captured_place.info.capture_kind;
 
-                debug!(
-                    "final_upvar_tys: place={:?} upvar_ty={:?} capture={:?}, mutability={:?}",
-                    captured_place.place, upvar_ty, capture, captured_place.mutability,
-                );
+                debug!(?captured_place.place, ?upvar_ty, ?capture, ?captured_place.mutability);
 
                 apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture, captured_place.region)
             })
@@ -679,6 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     match (p1.kind, p2.kind) {
                         // Paths are the same, continue to next loop.
                         (ProjectionKind::Deref, ProjectionKind::Deref) => {}
+                        (ProjectionKind::OpaqueCast, ProjectionKind::OpaqueCast) => {}
                         (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _))
                             if i1 == i2 => {}
 
@@ -701,10 +696,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             l @ (ProjectionKind::Index
                             | ProjectionKind::Subslice
                             | ProjectionKind::Deref
+                            | ProjectionKind::OpaqueCast
                             | ProjectionKind::Field(..)),
                             r @ (ProjectionKind::Index
                             | ProjectionKind::Subslice
                             | ProjectionKind::Deref
+                            | ProjectionKind::OpaqueCast
                             | ProjectionKind::Field(..)),
                         ) => bug!(
                             "ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})",
@@ -1890,6 +1887,7 @@ fn restrict_capture_precision(
                 return (place, curr_mode);
             }
             ProjectionKind::Deref => {}
+            ProjectionKind::OpaqueCast => {}
             ProjectionKind::Field(..) => {} // ignore
         }
     }
@@ -1946,6 +1944,7 @@ fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String
             ProjectionKind::Deref => String::from("Deref"),
             ProjectionKind::Index => String::from("Index"),
             ProjectionKind::Subslice => String::from("Subslice"),
+            ProjectionKind::OpaqueCast => String::from("OpaqueCast"),
         };
         if i != 0 {
             projections_str.push(',');
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 6f47623ec43..603681bbc99 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -210,7 +210,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
     // to use builtin indexing because the index type is known to be
     // usize-ish
     fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) {
-        if let hir::ExprKind::Index(ref base, ref index) = e.kind {
+        if let hir::ExprKind::Index(ref base, ref index, _) = e.kind {
             // All valid indexing looks like this; might encounter non-valid indexes at this point.
             let base_ty = self.typeck_results.expr_ty_adjusted_opt(base);
             if base_ty.is_none() {
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 433735e827b..6d5db3336cf 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -481,3 +481,31 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
         TypeTrace { cause: cause.clone(), values: Sigs(ExpectedFound::new(a_is_expected, a, b)) }
     }
 }
+
+impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
+    fn to_trace(
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: Self,
+        b: Self,
+    ) -> TypeTrace<'tcx> {
+        TypeTrace {
+            cause: cause.clone(),
+            values: ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)),
+        }
+    }
+}
+
+impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
+    fn to_trace(
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: Self,
+        b: Self,
+    ) -> TypeTrace<'tcx> {
+        TypeTrace {
+            cause: cause.clone(),
+            values: ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)),
+        }
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 54d901f20da..9d7a9fefd08 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -562,15 +562,9 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         V: TypeFoldable<TyCtxt<'tcx>>,
     {
         let needs_canonical_flags = if canonicalize_region_mode.any() {
-            TypeFlags::HAS_INFER |
-            TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
-            TypeFlags::HAS_TY_PLACEHOLDER |
-            TypeFlags::HAS_CT_PLACEHOLDER
+            TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_FREE_REGIONS
         } else {
-            TypeFlags::HAS_INFER
-                | TypeFlags::HAS_RE_PLACEHOLDER
-                | TypeFlags::HAS_TY_PLACEHOLDER
-                | TypeFlags::HAS_CT_PLACEHOLDER
+            TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER
         };
 
         // Fast path: nothing that needs to be canonicalized.
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 7739cf1ee05..75cca973306 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -351,6 +351,15 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
                 )
             }
         }
+        ty::RePlaceholder(_) => {
+            explain_free_region(
+                tcx,
+                &mut err,
+                &format!("hidden type `{}` captures ", hidden_ty),
+                hidden_region,
+                "",
+            );
+        }
         ty::ReError(_) => {
             err.delay_as_bug();
         }
@@ -1635,6 +1644,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         (false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id)))
                     }
                     ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
+                    ValuePairs::ExistentialTraitRef(_) => {
+                        (false, Mismatch::Fixed("existential trait ref"))
+                    }
+                    ValuePairs::ExistentialProjection(_) => {
+                        (false, Mismatch::Fixed("existential projection"))
+                    }
                 };
                 let Some(vals) = self.values_str(values) else {
                     // Derived error. Cancel the emitter.
@@ -2139,6 +2154,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::Regions(exp_found) => self.expected_found_str(exp_found),
             infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
             infer::Aliases(exp_found) => self.expected_found_str(exp_found),
+            infer::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found),
+            infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
             infer::TraitRefs(exp_found) => {
                 let pretty_exp_found = ty::error::ExpectedFound {
                     expected: exp_found.expected.print_only_trait_path(),
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index a73e84f94c4..aaabf1482e2 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -374,6 +374,8 @@ pub enum ValuePairs<'tcx> {
     TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
     PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
     Sigs(ExpectedFound<ty::FnSig<'tcx>>),
+    ExistentialTraitRef(ExpectedFound<ty::PolyExistentialTraitRef<'tcx>>),
+    ExistentialProjection(ExpectedFound<ty::PolyExistentialProjection<'tcx>>),
 }
 
 impl<'tcx> ValuePairs<'tcx> {
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 1b4c8ce120a..c4a7f717840 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -130,8 +130,6 @@ lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name
 lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}`
     .help = was set with `--cfg` but isn't in the `--check-cfg` expected values
 
-lint_builtin_unnameable_test_items = cannot test inner items
-
 lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed
 lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
 
@@ -169,8 +167,9 @@ lint_check_name_warning = {$msg}
 
 lint_command_line_source = `forbid` lint level was set on command line
 
-lint_confusable_identifier_pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}`
-    .label = this is where the previous identifier occurred
+lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as identifiers, which look alike
+    .current_use = this identifier can be confused with `{$existing_sym}`
+    .other_use = other identifier used here
 
 lint_cstring_ptr = getting the inner pointer of a temporary `CString`
     .as_ptr_label = this pointer will be invalid
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index cc6d5330c33..5e61073694f 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -35,7 +35,7 @@ use crate::{
         BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds,
         BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause,
         BuiltinUnexpectedCliConfigName, BuiltinUnexpectedCliConfigValue,
-        BuiltinUngatedAsyncFnTrackCaller, BuiltinUnnameableTestItems, BuiltinUnpermittedTypeInit,
+        BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
         BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe,
         BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
         BuiltinWhileTrue, SuggestChangingAssocTypes,
@@ -1259,8 +1259,8 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
 
 declare_lint! {
     /// The `ungated_async_fn_track_caller` lint warns when the
-    /// `#[track_caller]` attribute is used on an async function, method, or
-    /// closure, without enabling the corresponding unstable feature flag.
+    /// `#[track_caller]` attribute is used on an async function
+    /// without enabling the corresponding unstable feature flag.
     ///
     /// ### Example
     ///
@@ -1274,13 +1274,13 @@ declare_lint! {
     /// ### Explanation
     ///
     /// The attribute must be used in conjunction with the
-    /// [`closure_track_caller` feature flag]. Otherwise, the `#[track_caller]`
+    /// [`async_fn_track_caller` feature flag]. Otherwise, the `#[track_caller]`
     /// annotation will function as a no-op.
     ///
-    /// [`closure_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/closure-track-caller.html
+    /// [`async_fn_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/async-fn-track-caller.html
     UNGATED_ASYNC_FN_TRACK_CALLER,
     Warn,
-    "enabling track_caller on an async fn is a no-op unless the closure_track_caller feature is enabled"
+    "enabling track_caller on an async fn is a no-op unless the async_fn_track_caller feature is enabled"
 }
 
 declare_lint_pass!(
@@ -1300,7 +1300,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
         def_id: LocalDefId,
     ) {
         if fn_kind.asyncness() == IsAsync::Async
-            && !cx.tcx.features().closure_track_caller
+            && !cx.tcx.features().async_fn_track_caller
             // Now, check if the function has the `#[track_caller]` attribute
             && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
         {
@@ -1771,82 +1771,6 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
 }
 
 declare_lint! {
-    /// The `unnameable_test_items` lint detects [`#[test]`][test] functions
-    /// that are not able to be run by the test harness because they are in a
-    /// position where they are not nameable.
-    ///
-    /// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute
-    ///
-    /// ### Example
-    ///
-    /// ```rust,test
-    /// fn main() {
-    ///     #[test]
-    ///     fn foo() {
-    ///         // This test will not fail because it does not run.
-    ///         assert_eq!(1, 2);
-    ///     }
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// In order for the test harness to run a test, the test function must be
-    /// located in a position where it can be accessed from the crate root.
-    /// This generally means it must be defined in a module, and not anywhere
-    /// else such as inside another function. The compiler previously allowed
-    /// this without an error, so a lint was added as an alert that a test is
-    /// not being used. Whether or not this should be allowed has not yet been
-    /// decided, see [RFC 2471] and [issue #36629].
-    ///
-    /// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443
-    /// [issue #36629]: https://github.com/rust-lang/rust/issues/36629
-    UNNAMEABLE_TEST_ITEMS,
-    Warn,
-    "detects an item that cannot be named being marked as `#[test_case]`",
-    report_in_external_macro
-}
-
-pub struct UnnameableTestItems {
-    boundary: Option<hir::OwnerId>, // Id of the item under which things are not nameable
-    items_nameable: bool,
-}
-
-impl_lint_pass!(UnnameableTestItems => [UNNAMEABLE_TEST_ITEMS]);
-
-impl UnnameableTestItems {
-    pub fn new() -> Self {
-        Self { boundary: None, items_nameable: true }
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
-    fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
-        if self.items_nameable {
-            if let hir::ItemKind::Mod(..) = it.kind {
-            } else {
-                self.items_nameable = false;
-                self.boundary = Some(it.owner_id);
-            }
-            return;
-        }
-
-        let attrs = cx.tcx.hir().attrs(it.hir_id());
-        if let Some(attr) = attr::find_by_name(attrs, sym::rustc_test_marker) {
-            cx.emit_spanned_lint(UNNAMEABLE_TEST_ITEMS, attr.span, BuiltinUnnameableTestItems);
-        }
-    }
-
-    fn check_item_post(&mut self, _cx: &LateContext<'_>, it: &hir::Item<'_>) {
-        if !self.items_nameable && self.boundary == Some(it.owner_id) {
-            self.items_nameable = true;
-        }
-    }
-}
-
-declare_lint! {
     /// The `keyword_idents` lint detects edition keywords being used as an
     /// identifier.
     ///
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 9bd442e64e3..80bf53ea866 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -189,8 +189,6 @@ late_lint_methods!(
     [
         pub BuiltinCombinedLateLintPass,
         [
-            // Tracks state across modules
-            UnnameableTestItems: UnnameableTestItems::new(),
             // Tracks attributes of parents
             MissingDoc: MissingDoc::new(),
             // Builds a global list of all impls of `Debug`.
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 604daf2e90a..70311a5c576 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -250,7 +250,7 @@ impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> {
         rustc_session::parse::add_feature_diagnostics(
             diag,
             &self.parse_sess,
-            sym::closure_track_caller,
+            sym::async_fn_track_caller,
         );
         diag
     }
@@ -371,10 +371,6 @@ pub enum BuiltinEllipsisInclusiveRangePatternsLint {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_builtin_unnameable_test_items)]
-pub struct BuiltinUnnameableTestItems;
-
-#[derive(LintDiagnostic)]
 #[diag(lint_builtin_keyword_idents)]
 pub struct BuiltinKeywordIdents {
     pub kw: Ident,
@@ -1087,8 +1083,10 @@ pub struct IdentifierUncommonCodepoints;
 pub struct ConfusableIdentifierPair {
     pub existing_sym: Symbol,
     pub sym: Symbol,
-    #[label]
+    #[label(lint_other_use)]
     pub label: Span,
+    #[label(lint_current_use)]
+    pub main_label: Span,
 }
 
 #[derive(LintDiagnostic)]
diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs
index 4af879b4e91..62bb8c2c67d 100644
--- a/compiler/rustc_lint/src/non_ascii_idents.rs
+++ b/compiler/rustc_lint/src/non_ascii_idents.rs
@@ -222,6 +222,7 @@ impl EarlyLintPass for NonAsciiIdents {
                                     existing_sym: *existing_symbol,
                                     sym: symbol,
                                     label: *existing_span,
+                                    main_label: sp,
                                 },
                             );
                         }
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index a3c5ca4cda1..3db6b302790 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -653,7 +653,7 @@ trait UnusedDelimLint {
                     ExprKind::Call(fn_, _params) => fn_,
                     ExprKind::Cast(expr, _ty) => expr,
                     ExprKind::Type(expr, _ty) => expr,
-                    ExprKind::Index(base, _subscript) => base,
+                    ExprKind::Index(base, _subscript, _) => base,
                     _ => break,
                 };
                 if !classify::expr_requires_semi_to_be_stmt(innermost) {
@@ -830,7 +830,7 @@ trait UnusedDelimLint {
                 (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None, true)
             }
 
-            Index(_, ref value) => (value, UnusedDelimsCtx::IndexExpr, false, None, None, false),
+            Index(_, ref value, _) => (value, UnusedDelimsCtx::IndexExpr, false, None, None, false),
 
             Assign(_, ref value, _) | AssignOp(.., ref value) => {
                 (value, UnusedDelimsCtx::AssignedValue, false, None, None, false)
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 1a612731808..3747e562cec 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2847,6 +2847,45 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `unnameable_test_items` lint detects [`#[test]`][test] functions
+    /// that are not able to be run by the test harness because they are in a
+    /// position where they are not nameable.
+    ///
+    /// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute
+    ///
+    /// ### Example
+    ///
+    /// ```rust,test
+    /// fn main() {
+    ///     #[test]
+    ///     fn foo() {
+    ///         // This test will not fail because it does not run.
+    ///         assert_eq!(1, 2);
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In order for the test harness to run a test, the test function must be
+    /// located in a position where it can be accessed from the crate root.
+    /// This generally means it must be defined in a module, and not anywhere
+    /// else such as inside another function. The compiler previously allowed
+    /// this without an error, so a lint was added as an alert that a test is
+    /// not being used. Whether or not this should be allowed has not yet been
+    /// decided, see [RFC 2471] and [issue #36629].
+    ///
+    /// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443
+    /// [issue #36629]: https://github.com/rust-lang/rust/issues/36629
+    pub UNNAMEABLE_TEST_ITEMS,
+    Warn,
+    "detects an item that cannot be named being marked as `#[test_case]`",
+    report_in_external_macro
+}
+
+declare_lint! {
     /// The `useless_deprecated` lint detects deprecation attributes with no effect.
     ///
     /// ### Example
@@ -3403,6 +3442,7 @@ declare_lint_pass! {
         UNKNOWN_CRATE_TYPES,
         UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
         UNKNOWN_LINTS,
+        UNNAMEABLE_TEST_ITEMS,
         UNNAMEABLE_TYPES,
         UNREACHABLE_CODE,
         UNREACHABLE_PATTERNS,
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index d72053ca985..f12094a271f 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -30,6 +30,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
 use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
+use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{self, AssocItemContainer, SymbolName, Ty, TyCtxt};
 use rustc_middle::util::common::to_readable_str;
 use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
@@ -1034,7 +1035,7 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
     }
 }
 
-fn should_encode_variances(def_kind: DefKind) -> bool {
+fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: DefKind) -> bool {
     match def_kind {
         DefKind::Struct
         | DefKind::Union
@@ -1053,7 +1054,6 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
         | DefKind::Static(..)
         | DefKind::Const
         | DefKind::ForeignMod
-        | DefKind::TyAlias
         | DefKind::Impl { .. }
         | DefKind::Trait
         | DefKind::TraitAlias
@@ -1067,6 +1067,10 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
         | DefKind::Closure
         | DefKind::Generator
         | DefKind::ExternCrate => false,
+        DefKind::TyAlias => {
+            tcx.features().lazy_type_alias
+                || tcx.type_of(def_id).instantiate_identity().has_opaque_types()
+        }
     }
 }
 
@@ -1349,7 +1353,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 self.encode_default_body_stability(def_id);
                 self.encode_deprecation(def_id);
             }
-            if should_encode_variances(def_kind) {
+            if should_encode_variances(tcx, def_id, def_kind) {
                 let v = self.tcx.variances_of(def_id);
                 record_array!(self.tables.variances_of[def_id] <- v);
             }
diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs
index 8a22de931c3..32f3a177508 100644
--- a/compiler/rustc_middle/src/hir/place.rs
+++ b/compiler/rustc_middle/src/hir/place.rs
@@ -36,6 +36,10 @@ pub enum ProjectionKind {
 
     /// A subslice covering a range of values like `B[x..y]`.
     Subslice,
+
+    /// A conversion from an opaque type to its hidden type so we can
+    /// do further projections on it.
+    OpaqueCast,
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 1189dcdfcbb..a02f9a9f796 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -749,7 +749,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    /// Gets a map with the variance of every item; use `item_variance` instead.
+    /// Gets a map with the variance of every item; use `variances_of` instead.
     query crate_variances(_: ()) -> &'tcx ty::CrateVariancesMap<'tcx> {
         arena_cache
         desc { "computing the variances for items in this crate" }
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index b21a00e4122..9d63d291854 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -1,7 +1,6 @@
 use std::ops::ControlFlow;
 
 use rustc_data_structures::intern::Interned;
-use rustc_query_system::cache::Cache;
 
 use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints};
 use crate::traits::query::NoSolution;
@@ -11,9 +10,10 @@ use crate::ty::{
     TypeVisitor,
 };
 
+mod cache;
 pub mod inspect;
 
-pub type EvaluationCache<'tcx> = Cache<CanonicalInput<'tcx>, QueryResult<'tcx>>;
+pub use cache::{CacheData, EvaluationCache};
 
 /// A goal is a statement, i.e. `predicate`, we want to prove
 /// given some assumptions, i.e. `param_env`.
@@ -147,7 +147,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> {
 }
 
 /// Additional constraints returned on success.
-#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)]
+#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)]
 pub struct ExternalConstraintsData<'tcx> {
     // FIXME: implement this.
     pub region_constraints: QueryRegionConstraints<'tcx>,
diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs
new file mode 100644
index 00000000000..9898b0019bb
--- /dev/null
+++ b/compiler/rustc_middle/src/traits/solve/cache.rs
@@ -0,0 +1,100 @@
+use super::{CanonicalInput, QueryResult};
+use crate::ty::TyCtxt;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::sync::Lock;
+use rustc_query_system::cache::WithDepNode;
+use rustc_query_system::dep_graph::DepNodeIndex;
+use rustc_session::Limit;
+/// The trait solver cache used by `-Ztrait-solver=next`.
+///
+/// FIXME(@lcnr): link to some official documentation of how
+/// this works.
+#[derive(Default)]
+pub struct EvaluationCache<'tcx> {
+    map: Lock<FxHashMap<CanonicalInput<'tcx>, CacheEntry<'tcx>>>,
+}
+
+pub struct CacheData<'tcx> {
+    pub result: QueryResult<'tcx>,
+    pub reached_depth: usize,
+    pub encountered_overflow: bool,
+}
+
+impl<'tcx> EvaluationCache<'tcx> {
+    /// Insert a final result into the global cache.
+    pub fn insert(
+        &self,
+        key: CanonicalInput<'tcx>,
+        reached_depth: usize,
+        did_overflow: bool,
+        cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
+        dep_node: DepNodeIndex,
+        result: QueryResult<'tcx>,
+    ) {
+        let mut map = self.map.borrow_mut();
+        let entry = map.entry(key).or_default();
+        let data = WithDepNode::new(dep_node, result);
+        entry.cycle_participants.extend(cycle_participants);
+        if did_overflow {
+            entry.with_overflow.insert(reached_depth, data);
+        } else {
+            entry.success = Some(Success { data, reached_depth });
+        }
+    }
+
+    /// Try to fetch a cached result, checking the recursion limit
+    /// and handling root goals of coinductive cycles.
+    ///
+    /// If this returns `Some` the cache result can be used.
+    pub fn get(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        key: CanonicalInput<'tcx>,
+        cycle_participant_in_stack: impl FnOnce(&FxHashSet<CanonicalInput<'tcx>>) -> bool,
+        available_depth: Limit,
+    ) -> Option<CacheData<'tcx>> {
+        let map = self.map.borrow();
+        let entry = map.get(&key)?;
+
+        if cycle_participant_in_stack(&entry.cycle_participants) {
+            return None;
+        }
+
+        if let Some(ref success) = entry.success {
+            if available_depth.value_within_limit(success.reached_depth) {
+                return Some(CacheData {
+                    result: success.data.get(tcx),
+                    reached_depth: success.reached_depth,
+                    encountered_overflow: false,
+                });
+            }
+        }
+
+        entry.with_overflow.get(&available_depth.0).map(|e| CacheData {
+            result: e.get(tcx),
+            reached_depth: available_depth.0,
+            encountered_overflow: true,
+        })
+    }
+}
+
+struct Success<'tcx> {
+    data: WithDepNode<QueryResult<'tcx>>,
+    reached_depth: usize,
+}
+
+/// The cache entry for a goal `CanonicalInput`.
+///
+/// This contains results whose computation never hit the
+/// recursion limit in `success`, and all results which hit
+/// the recursion limit in `with_overflow`.
+#[derive(Default)]
+struct CacheEntry<'tcx> {
+    success: Option<Success<'tcx>>,
+    /// We have to be careful when caching roots of cycles.
+    ///
+    /// See the doc comment of `StackEntry::cycle_participants` for more
+    /// details.
+    cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
+    with_overflow: FxHashMap<usize, WithDepNode<QueryResult<'tcx>>>,
+}
diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs
index e793f481995..4e2af3816ac 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect.rs
@@ -73,12 +73,15 @@ pub struct GoalCandidate<'tcx> {
 pub enum CandidateKind<'tcx> {
     /// Probe entered when normalizing the self ty during candidate assembly
     NormalizedSelfTyAssembly,
-    DynUpcastingAssembly,
     /// A normal candidate for proving a goal
-    Candidate {
-        name: String,
-        result: QueryResult<'tcx>,
-    },
+    Candidate { name: String, result: QueryResult<'tcx> },
+    /// Used in the probe that wraps normalizing the non-self type for the unsize
+    /// trait, which is also structurally matched on.
+    UnsizeAssembly,
+    /// During upcasting from some source object to target object type, used to
+    /// do a probe to find out what projection type(s) may be used to prove that
+    /// the source type upholds all of the target type's object bounds.
+    UpcastProbe,
 }
 impl Debug for GoalCandidate<'_> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index f1e567e9bf8..8759fecb05a 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -100,8 +100,11 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
             CandidateKind::NormalizedSelfTyAssembly => {
                 writeln!(self.f, "NORMALIZING SELF TY FOR ASSEMBLY:")
             }
-            CandidateKind::DynUpcastingAssembly => {
-                writeln!(self.f, "ASSEMBLING CANDIDATES FOR DYN UPCASTING:")
+            CandidateKind::UnsizeAssembly => {
+                writeln!(self.f, "ASSEMBLING CANDIDATES FOR UNSIZING:")
+            }
+            CandidateKind::UpcastProbe => {
+                writeln!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:")
             }
             CandidateKind::Candidate { name, result } => {
                 writeln!(self.f, "CANDIDATE {name}: {result:?}")
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 42f22604975..2e5c6a44579 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -174,6 +174,8 @@ impl<'tcx> CapturedPlace<'tcx> {
                 // Ignore derefs for now, as they are likely caused by
                 // autoderefs that don't appear in the original code.
                 HirProjectionKind::Deref => {}
+                // Just change the type to the hidden type, so we can actually project.
+                HirProjectionKind::OpaqueCast => {}
                 proj => bug!("Unexpected projection {:?} in captured place", proj),
             }
             ty = proj.ty;
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 6b0f0132062..48aa25dba6d 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1338,12 +1338,25 @@ impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
     }
 }
 
+impl<'tcx> ToPredicate<'tcx> for ProjectionPredicate<'tcx> {
+    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        ty::Binder::dummy(PredicateKind::Clause(ClauseKind::Projection(self))).to_predicate(tcx)
+    }
+}
+
 impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         self.map_bound(|p| PredicateKind::Clause(ClauseKind::Projection(p))).to_predicate(tcx)
     }
 }
 
+impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ProjectionPredicate<'tcx> {
+    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
+        let p: Predicate<'tcx> = self.to_predicate(tcx);
+        p.expect_clause()
+    }
+}
+
 impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
         let p: Predicate<'tcx> = self.to_predicate(tcx);
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 6e68022031a..d3fd49150ba 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2734,8 +2734,9 @@ forward_display_to_print! {
     // HACK(eddyb) these are exhaustive instead of generic,
     // because `for<'tcx>` isn't possible yet.
     ty::PolyExistentialPredicate<'tcx>,
+    ty::PolyExistentialProjection<'tcx>,
+    ty::PolyExistentialTraitRef<'tcx>,
     ty::Binder<'tcx, ty::TraitRef<'tcx>>,
-    ty::Binder<'tcx, ty::ExistentialTraitRef<'tcx>>,
     ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
     ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>,
     ty::Binder<'tcx, ty::FnSig<'tcx>>,
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 520bb55e031..156eda477ad 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -88,14 +88,10 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
         self.has_type_flags(TypeFlags::HAS_INFER)
     }
     fn has_placeholders(&self) -> bool {
-        self.has_type_flags(
-            TypeFlags::HAS_RE_PLACEHOLDER
-                | TypeFlags::HAS_TY_PLACEHOLDER
-                | TypeFlags::HAS_CT_PLACEHOLDER,
-        )
+        self.has_type_flags(TypeFlags::HAS_PLACEHOLDER)
     }
     fn has_non_region_placeholders(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER)
+        self.has_type_flags(TypeFlags::HAS_PLACEHOLDER - TypeFlags::HAS_RE_PLACEHOLDER)
     }
     fn has_param(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_PARAM)
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 7756d5d4879..2e7ef265a93 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -236,6 +236,9 @@ fn strip_prefix<'a, 'tcx>(
                 }
                 assert_matches!(iter.next(), Some(ProjectionElem::Field(..)));
             }
+            HirProjectionKind::OpaqueCast => {
+                assert_matches!(iter.next(), Some(ProjectionElem::OpaqueCast(..)));
+            }
             HirProjectionKind::Index | HirProjectionKind::Subslice => {
                 bug!("unexpected projection kind: {:?}", projection);
             }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index ff4620948fa..994ac8a3286 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -469,11 +469,17 @@ impl<'tcx> Cx<'tcx> {
                 }
             }
 
-            hir::ExprKind::Index(ref lhs, ref index) => {
+            hir::ExprKind::Index(ref lhs, ref index, brackets_span) => {
                 if self.typeck_results().is_method_call(expr) {
                     let lhs = self.mirror_expr(lhs);
                     let index = self.mirror_expr(index);
-                    self.overloaded_place(expr, expr_ty, None, Box::new([lhs, index]), expr.span)
+                    self.overloaded_place(
+                        expr,
+                        expr_ty,
+                        None,
+                        Box::new([lhs, index]),
+                        brackets_span,
+                    )
                 } else {
                     ExprKind::Index { lhs: self.mirror_expr(lhs), index: self.mirror_expr(index) }
                 }
@@ -1072,6 +1078,9 @@ impl<'tcx> Cx<'tcx> {
                     variant_index,
                     name: field,
                 },
+                HirProjectionKind::OpaqueCast => {
+                    ExprKind::Use { source: self.thir.exprs.push(captured_place_expr) }
+                }
                 HirProjectionKind::Index | HirProjectionKind::Subslice => {
                     // We don't capture these projections, so we can ignore them here
                     continue;
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index c0459789805..e409c7c6781 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -857,7 +857,7 @@ impl<'a> Parser<'a> {
             let msg = format!(
                 "cast cannot be followed by {}",
                 match with_postfix.kind {
-                    ExprKind::Index(_, _) => "indexing",
+                    ExprKind::Index(..) => "indexing",
                     ExprKind::Try(_) => "`?`",
                     ExprKind::Field(_, _) => "a field access",
                     ExprKind::MethodCall(_) => "a method call",
@@ -1304,7 +1304,10 @@ impl<'a> Parser<'a> {
         let index = self.parse_expr()?;
         self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?;
         self.expect(&token::CloseDelim(Delimiter::Bracket))?;
-        Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index)))
+        Ok(self.mk_expr(
+            lo.to(self.prev_token.span),
+            self.mk_index(base, index, open_delim_span.to(self.prev_token.span)),
+        ))
     }
 
     /// Assuming we have just parsed `.`, continue parsing into an expression.
@@ -3366,8 +3369,8 @@ impl<'a> Parser<'a> {
         ExprKind::Binary(binop, lhs, rhs)
     }
 
-    fn mk_index(&self, expr: P<Expr>, idx: P<Expr>) -> ExprKind {
-        ExprKind::Index(expr, idx)
+    fn mk_index(&self, expr: P<Expr>, idx: P<Expr>, brackets_span: Span) -> ExprKind {
+        ExprKind::Index(expr, idx, brackets_span)
     }
 
     fn mk_call(&self, f: P<Expr>, args: ThinVec<P<Expr>>) -> ExprKind {
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 15757a0f1ad..0c0b8b6d094 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -1061,7 +1061,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 self.propagate_through_expr(&l, ln)
             }
 
-            hir::ExprKind::Index(ref l, ref r) | hir::ExprKind::Binary(_, ref l, ref r) => {
+            hir::ExprKind::Index(ref l, ref r, _) | hir::ExprKind::Binary(_, ref l, ref r) => {
                 let r_succ = self.propagate_through_expr(&r, succ);
                 self.propagate_through_expr(&l, r_succ)
             }
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index e02cf38b671..584355df802 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 [lib]
 
 [dependencies]
-parking_lot = "0.11"
+parking_lot = "0.12"
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index b87757a3e1a..3803f7eca0a 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -1,4 +1,3 @@
-use parking_lot::Mutex;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::profiling::{EventId, QueryInvocationId, SelfProfilerRef};
@@ -88,7 +87,7 @@ pub struct DepGraphData<K: DepKind> {
 
     colors: DepNodeColorMap,
 
-    processed_side_effects: Mutex<FxHashSet<DepNodeIndex>>,
+    processed_side_effects: Lock<FxHashSet<DepNodeIndex>>,
 
     /// When we load, there may be `.o` files, cached MIR, or other such
     /// things available to us. If we find that they are not dirty, we
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index d2140161f1d..bfc51da170d 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -21,12 +21,11 @@ use {
     parking_lot::{Condvar, Mutex},
     rayon_core,
     rustc_data_structures::fx::FxHashSet,
-    rustc_data_structures::sync::Lock,
-    rustc_data_structures::sync::Lrc,
     rustc_data_structures::{defer, jobserver},
     rustc_span::DUMMY_SP,
     std::iter,
     std::process,
+    std::sync::Arc,
 };
 
 /// Represents a span and a query key.
@@ -191,7 +190,7 @@ struct QueryWaiter<D: DepKind> {
     query: Option<QueryJobId>,
     condvar: Condvar,
     span: Span,
-    cycle: Lock<Option<CycleError<D>>>,
+    cycle: Mutex<Option<CycleError<D>>>,
 }
 
 #[cfg(parallel_compiler)]
@@ -205,20 +204,20 @@ impl<D: DepKind> QueryWaiter<D> {
 #[cfg(parallel_compiler)]
 struct QueryLatchInfo<D: DepKind> {
     complete: bool,
-    waiters: Vec<Lrc<QueryWaiter<D>>>,
+    waiters: Vec<Arc<QueryWaiter<D>>>,
 }
 
 #[cfg(parallel_compiler)]
 #[derive(Clone)]
 pub(super) struct QueryLatch<D: DepKind> {
-    info: Lrc<Mutex<QueryLatchInfo<D>>>,
+    info: Arc<Mutex<QueryLatchInfo<D>>>,
 }
 
 #[cfg(parallel_compiler)]
 impl<D: DepKind> QueryLatch<D> {
     fn new() -> Self {
         QueryLatch {
-            info: Lrc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })),
+            info: Arc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })),
         }
     }
 
@@ -229,11 +228,11 @@ impl<D: DepKind> QueryLatch<D> {
         span: Span,
     ) -> Result<(), CycleError<D>> {
         let waiter =
-            Lrc::new(QueryWaiter { query, span, cycle: Lock::new(None), condvar: Condvar::new() });
+            Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() });
         self.wait_on_inner(&waiter);
         // FIXME: Get rid of this lock. We have ownership of the QueryWaiter
-        // although another thread may still have a Lrc reference so we cannot
-        // use Lrc::get_mut
+        // although another thread may still have a Arc reference so we cannot
+        // use Arc::get_mut
         let mut cycle = waiter.cycle.lock();
         match cycle.take() {
             None => Ok(()),
@@ -242,7 +241,7 @@ impl<D: DepKind> QueryLatch<D> {
     }
 
     /// Awaits the caller on this latch by blocking the current thread.
-    fn wait_on_inner(&self, waiter: &Lrc<QueryWaiter<D>>) {
+    fn wait_on_inner(&self, waiter: &Arc<QueryWaiter<D>>) {
         let mut info = self.info.lock();
         if !info.complete {
             // We push the waiter on to the `waiters` list. It can be accessed inside
@@ -276,7 +275,7 @@ impl<D: DepKind> QueryLatch<D> {
 
     /// Removes a single waiter from the list of waiters.
     /// This is used to break query cycles.
-    fn extract_waiter(&self, waiter: usize) -> Lrc<QueryWaiter<D>> {
+    fn extract_waiter(&self, waiter: usize) -> Arc<QueryWaiter<D>> {
         let mut info = self.info.lock();
         debug_assert!(!info.complete);
         // Remove the waiter from the list of waiters
@@ -428,7 +427,7 @@ where
 fn remove_cycle<D: DepKind>(
     query_map: &QueryMap<D>,
     jobs: &mut Vec<QueryJobId>,
-    wakelist: &mut Vec<Lrc<QueryWaiter<D>>>,
+    wakelist: &mut Vec<Arc<QueryWaiter<D>>>,
 ) -> bool {
     let mut visited = FxHashSet::default();
     let mut stack = Vec::new();
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 0e9d74480a9..7b590d16d8c 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -4269,7 +4269,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             ExprKind::ConstBlock(ref ct) => {
                 self.resolve_anon_const(ct, AnonConstKind::InlineConst);
             }
-            ExprKind::Index(ref elem, ref idx) => {
+            ExprKind::Index(ref elem, ref idx, _) => {
                 self.resolve_expr(elem, Some(expr));
                 self.visit_expr(idx);
             }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index ad22e7c703d..ac745d16161 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1350,18 +1350,15 @@ fn default_emitter(
                 );
                 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
             } else {
-                let emitter = EmitterWriter::stderr(
-                    color_config,
-                    Some(source_map),
-                    bundle,
-                    fallback_bundle,
-                    short,
-                    sopts.unstable_opts.teach,
-                    sopts.diagnostic_width,
-                    macro_backtrace,
-                    track_diagnostics,
-                    terminal_url,
-                );
+                let emitter = EmitterWriter::stderr(color_config, fallback_bundle)
+                    .fluent_bundle(bundle)
+                    .sm(Some(source_map))
+                    .short_message(short)
+                    .teach(sopts.unstable_opts.teach)
+                    .diagnostic_width(sopts.diagnostic_width)
+                    .macro_backtrace(macro_backtrace)
+                    .track_diagnostics(track_diagnostics)
+                    .terminal_url(terminal_url);
                 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
             }
         }
@@ -1794,18 +1791,7 @@ fn mk_emitter(output: ErrorOutputType) -> Box<dyn Emitter + sync::Send + 'static
     let emitter: Box<dyn Emitter + sync::Send> = match output {
         config::ErrorOutputType::HumanReadable(kind) => {
             let (short, color_config) = kind.unzip();
-            Box::new(EmitterWriter::stderr(
-                color_config,
-                None,
-                None,
-                fallback_bundle,
-                short,
-                false,
-                None,
-                false,
-                false,
-                TerminalUrl::No,
-            ))
+            Box::new(EmitterWriter::stderr(color_config, fallback_bundle).short_message(short))
         }
         config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(
             pretty,
diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs
index 4811bb2c354..96a118e590f 100644
--- a/compiler/rustc_span/src/edit_distance.rs
+++ b/compiler/rustc_span/src/edit_distance.rs
@@ -248,9 +248,9 @@ fn find_match_by_sorted_words(iter_names: &[Symbol], lookup: &str) -> Option<Sym
     })
 }
 
-fn sort_by_words(name: &str) -> String {
+fn sort_by_words(name: &str) -> Vec<&str> {
     let mut split_words: Vec<&str> = name.split('_').collect();
     // We are sorting primitive &strs and can use unstable sort here.
     split_words.sort_unstable();
-    split_words.join("_")
+    split_words
 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 9cff8a688ff..44820ae6f72 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -400,6 +400,7 @@ symbols! {
         async_await,
         async_closure,
         async_fn_in_trait,
+        async_fn_track_caller,
         atomic,
         atomic_mod,
         atomics,
diff --git a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
index 75a65a26849..6389d68641a 100644
--- a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
             linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
             linker: Some("rust-lld".into()),
             cpu: "generic-rv32".into(),
-            max_atomic_width: Some(0),
+            max_atomic_width: Some(32),
             atomic_cas: false,
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs
index f2242bbe087..a177a73483f 100644
--- a/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
             linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
             linker: Some("rust-lld".into()),
             cpu: "generic-rv32".into(),
-            max_atomic_width: Some(0),
+            max_atomic_width: Some(32),
             atomic_cas: false,
             features: "+m".into(),
             panic_strategy: PanicStrategy::Abort,
diff --git a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
index 01e773fae97..fd620696cb2 100644
--- a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
             linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
             linker: Some("rust-lld".into()),
             cpu: "generic-rv32".into(),
-            max_atomic_width: Some(0),
+            max_atomic_width: Some(32),
             atomic_cas: false,
             features: "+m,+c".into(),
             panic_strategy: PanicStrategy::Abort,
diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
index 1b4af95cb8a..6b839d64b87 100644
--- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs
+++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
@@ -162,7 +162,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         self.add_goal(Goal::new(
             self.tcx(),
             param_env,
-            ty::Binder::dummy(ty::ProjectionPredicate { projection_ty: alias, term: other }),
+            ty::ProjectionPredicate { projection_ty: alias, term: other },
         ));
 
         Ok(())
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 8bf003f863e..267f345c062 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -1,6 +1,5 @@
 //! Code shared by trait and projection goals for candidate assembly.
 
-use super::search_graph::OverflowHandler;
 use super::{EvalCtxt, SolverMode};
 use crate::traits::coherence;
 use rustc_hir::def_id::DefId;
@@ -315,7 +314,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             return ambig;
         }
 
-        let mut candidates = self.assemble_candidates_via_self_ty(goal);
+        let mut candidates = self.assemble_candidates_via_self_ty(goal, 0);
 
         self.assemble_blanket_impl_candidates(goal, &mut candidates);
 
@@ -351,6 +350,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     fn assemble_candidates_via_self_ty<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
+        num_steps: usize,
     ) -> Vec<Candidate<'tcx>> {
         debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
         if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) {
@@ -369,7 +369,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
 
         self.assemble_coherence_unknowable_candidates(goal, &mut candidates);
 
-        self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates);
+        self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates, num_steps);
 
         candidates
     }
@@ -393,49 +393,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         &mut self,
         goal: Goal<'tcx, G>,
         candidates: &mut Vec<Candidate<'tcx>>,
+        num_steps: usize,
     ) {
         let tcx = self.tcx();
         let &ty::Alias(_, projection_ty) = goal.predicate.self_ty().kind() else { return };
 
-        let normalized_self_candidates: Result<_, NoSolution> =
-            self.probe(|_| CandidateKind::NormalizedSelfTyAssembly).enter(|ecx| {
-                ecx.with_incremented_depth(
-                    |ecx| {
-                        let result = ecx.evaluate_added_goals_and_make_canonical_response(
-                            Certainty::OVERFLOW,
-                        )?;
-                        Ok(vec![Candidate {
-                            source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
-                            result,
-                        }])
-                    },
-                    |ecx| {
-                        let normalized_ty = ecx.next_ty_infer();
-                        let normalizes_to_goal = goal.with(
-                            tcx,
-                            ty::Binder::dummy(ty::ProjectionPredicate {
-                                projection_ty,
-                                term: normalized_ty.into(),
-                            }),
-                        );
-                        ecx.add_goal(normalizes_to_goal);
-                        let _ = ecx.try_evaluate_added_goals().inspect_err(|_| {
-                            debug!("self type normalization failed");
-                        })?;
-                        let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty);
-                        debug!(?normalized_ty, "self type normalized");
-                        // NOTE: Alternatively we could call `evaluate_goal` here and only
-                        // have a `Normalized` candidate. This doesn't work as long as we
-                        // use `CandidateSource` in winnowing.
-                        let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
-                        Ok(ecx.assemble_candidates_via_self_ty(goal))
-                    },
-                )
-            });
-
-        if let Ok(normalized_self_candidates) = normalized_self_candidates {
-            candidates.extend(normalized_self_candidates);
-        }
+        candidates.extend(self.probe(|_| CandidateKind::NormalizedSelfTyAssembly).enter(|ecx| {
+            if num_steps < ecx.local_overflow_limit() {
+                let normalized_ty = ecx.next_ty_infer();
+                let normalizes_to_goal = goal.with(
+                    tcx,
+                    ty::ProjectionPredicate { projection_ty, term: normalized_ty.into() },
+                );
+                ecx.add_goal(normalizes_to_goal);
+                if let Err(NoSolution) = ecx.try_evaluate_added_goals() {
+                    debug!("self type normalization failed");
+                    return vec![];
+                }
+                let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty);
+                debug!(?normalized_ty, "self type normalized");
+                // NOTE: Alternatively we could call `evaluate_goal` here and only
+                // have a `Normalized` candidate. This doesn't work as long as we
+                // use `CandidateSource` in winnowing.
+                let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
+                ecx.assemble_candidates_via_self_ty(goal, num_steps + 1)
+            } else {
+                match ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW) {
+                    Ok(result) => vec![Candidate {
+                        source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
+                        result,
+                    }],
+                    Err(NoSolution) => vec![],
+                }
+            }
+        }));
     }
 
     #[instrument(level = "debug", skip_all)]
@@ -533,7 +524,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (),
 
             // FIXME: These should ideally not exist as a self type. It would be nice for
-            // the builtin auto trait impls of generators should instead directly recurse
+            // the builtin auto trait impls of generators to instead directly recurse
             // into the witness.
             ty::GeneratorWitness(_) | ty::GeneratorWitnessMIR(_, _) => (),
 
diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
index 88771f90756..a9d182abfb7 100644
--- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
@@ -207,23 +207,18 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
         t
     }
 
-    fn fold_region(&mut self, mut r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match self.canonicalize_mode {
-            CanonicalizeMode::Input => {
-                // Don't resolve infer vars in input, since it affects
-                // caching and may cause trait selection bugs which rely
-                // on regions to be equal.
-            }
-            CanonicalizeMode::Response { .. } => {
-                if let ty::ReVar(vid) = *r {
-                    r = self
-                        .infcx
-                        .inner
-                        .borrow_mut()
-                        .unwrap_region_constraints()
-                        .opportunistic_resolve_var(self.infcx.tcx, vid);
-                }
-            }
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        if let ty::ReVar(vid) = *r {
+            let resolved_region = self
+                .infcx
+                .inner
+                .borrow_mut()
+                .unwrap_region_constraints()
+                .opportunistic_resolve_var(self.infcx.tcx, vid);
+            assert_eq!(
+                r, resolved_region,
+                "region var should have been resolved, {r} -> {resolved_region}"
+            );
         }
 
         let kind = match *r {
@@ -278,38 +273,22 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
         ty::Region::new_late_bound(self.interner(), self.binder_index, br)
     }
 
-    fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         let kind = match *t.kind() {
-            ty::Infer(ty::TyVar(mut vid)) => {
-                // We need to canonicalize the *root* of our ty var.
-                // This is so that our canonical response correctly reflects
-                // any equated inference vars correctly!
-                let root_vid = self.infcx.root_var(vid);
-                if root_vid != vid {
-                    t = Ty::new_var(self.infcx.tcx, root_vid);
-                    vid = root_vid;
-                }
-
-                match self.infcx.probe_ty_var(vid) {
-                    Ok(t) => return self.fold_ty(t),
-                    Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
-                }
+            ty::Infer(ty::TyVar(vid)) => {
+                assert_eq!(self.infcx.root_var(vid), vid, "ty vid should have been resolved");
+                let Err(ui) = self.infcx.probe_ty_var(vid) else {
+                    bug!("ty var should have been resolved: {t}");
+                };
+                CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
             }
             ty::Infer(ty::IntVar(vid)) => {
-                let nt = self.infcx.opportunistic_resolve_int_var(vid);
-                if nt != t {
-                    return self.fold_ty(nt);
-                } else {
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
-                }
+                assert_eq!(self.infcx.opportunistic_resolve_int_var(vid), t);
+                CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
             }
             ty::Infer(ty::FloatVar(vid)) => {
-                let nt = self.infcx.opportunistic_resolve_float_var(vid);
-                if nt != t {
-                    return self.fold_ty(nt);
-                } else {
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::Float)
-                }
+                assert_eq!(self.infcx.opportunistic_resolve_float_var(vid), t);
+                CanonicalVarKind::Ty(CanonicalTyVarKind::Float)
             }
             ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
                 bug!("fresh var during canonicalization: {t:?}")
@@ -372,22 +351,19 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
         Ty::new_bound(self.infcx.tcx, self.binder_index, bt)
     }
 
-    fn fold_const(&mut self, mut c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
         let kind = match c.kind() {
-            ty::ConstKind::Infer(ty::InferConst::Var(mut vid)) => {
-                // We need to canonicalize the *root* of our const var.
-                // This is so that our canonical response correctly reflects
-                // any equated inference vars correctly!
-                let root_vid = self.infcx.root_const_var(vid);
-                if root_vid != vid {
-                    c = ty::Const::new_var(self.infcx.tcx, root_vid, c.ty());
-                    vid = root_vid;
-                }
-
-                match self.infcx.probe_const_var(vid) {
-                    Ok(c) => return self.fold_const(c),
-                    Err(universe) => CanonicalVarKind::Const(universe, c.ty()),
-                }
+            ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
+                assert_eq!(
+                    self.infcx.root_const_var(vid),
+                    vid,
+                    "const var should have been resolved"
+                );
+                let Err(ui) = self.infcx.probe_const_var(vid) else {
+                    bug!("const var should have been resolved");
+                };
+                // FIXME: we should fold this ty eventually
+                CanonicalVarKind::Const(ui, c.ty())
             }
             ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
                 bug!("fresh var during canonicalization: {c:?}")
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index 485bc912c44..5ec9ddfe64a 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -1,20 +1,21 @@
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::canonical::CanonicalVarValues;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{
-    DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, RegionVariableOrigin,
-    TyCtxtInferExt,
+    DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt,
 };
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::ObligationCause;
+use rustc_middle::infer::canonical::CanonicalVarInfos;
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::traits::solve::inspect;
 use rustc_middle::traits::solve::{
     CanonicalInput, CanonicalResponse, Certainty, IsNormalizesToHack, PredefinedOpaques,
     PredefinedOpaquesData, QueryResult,
 };
-use rustc_middle::traits::DefiningAnchor;
+use rustc_middle::traits::{specialization_graph, DefiningAnchor};
 use rustc_middle::ty::{
     self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
     TypeVisitableExt, TypeVisitor,
@@ -24,11 +25,10 @@ use rustc_span::DUMMY_SP;
 use std::io::Write;
 use std::ops::ControlFlow;
 
-use crate::traits::specialization_graph;
 use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
 
 use super::inspect::ProofTreeBuilder;
-use super::search_graph::{self, OverflowHandler};
+use super::search_graph;
 use super::SolverMode;
 use super::{search_graph::SearchGraph, Goal};
 pub use select::InferCtxtSelectExt;
@@ -55,6 +55,9 @@ pub struct EvalCtxt<'a, 'tcx> {
     /// the job already.
     infcx: &'a InferCtxt<'tcx>,
 
+    /// The variable info for the `var_values`, only used to make an ambiguous response
+    /// with no constraints.
+    variables: CanonicalVarInfos<'tcx>,
     pub(super) var_values: CanonicalVarValues<'tcx>,
 
     predefined_opaques_in_body: PredefinedOpaques<'tcx>,
@@ -171,6 +174,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         self.search_graph.solver_mode()
     }
 
+    pub(super) fn local_overflow_limit(&self) -> usize {
+        self.search_graph.local_overflow_limit()
+    }
+
     /// Creates a root evaluation context and search graph. This should only be
     /// used from outside of any evaluation, and other methods should be preferred
     /// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]).
@@ -184,18 +191,19 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
 
         let mut ecx = EvalCtxt {
             search_graph: &mut search_graph,
-            infcx: infcx,
+            infcx,
+            nested_goals: NestedGoals::new(),
+            inspect: ProofTreeBuilder::new_maybe_root(infcx.tcx, generate_proof_tree),
+
             // Only relevant when canonicalizing the response,
             // which we don't do within this evaluation context.
             predefined_opaques_in_body: infcx
                 .tcx
                 .mk_predefined_opaques_in_body(PredefinedOpaquesData::default()),
-            // Only relevant when canonicalizing the response.
             max_input_universe: ty::UniverseIndex::ROOT,
+            variables: ty::List::empty(),
             var_values: CanonicalVarValues::dummy(),
-            nested_goals: NestedGoals::new(),
             tainted: Ok(()),
-            inspect: ProofTreeBuilder::new_maybe_root(infcx.tcx, generate_proof_tree),
         };
         let result = f(&mut ecx);
 
@@ -245,6 +253,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
 
         let mut ecx = EvalCtxt {
             infcx,
+            variables: canonical_input.variables,
             var_values,
             predefined_opaques_in_body: input.predefined_opaques_in_body,
             max_input_universe: canonical_input.max_universe,
@@ -300,24 +309,26 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         // Deal with overflow, caching, and coinduction.
         //
         // The actual solver logic happens in `ecx.compute_goal`.
-        search_graph.with_new_goal(
-            tcx,
-            canonical_input,
-            goal_evaluation,
-            |search_graph, goal_evaluation| {
-                EvalCtxt::enter_canonical(
-                    tcx,
-                    search_graph,
-                    canonical_input,
-                    goal_evaluation,
-                    |ecx, goal| {
-                        let result = ecx.compute_goal(goal);
-                        ecx.inspect.query_result(result);
-                        result
-                    },
-                )
-            },
-        )
+        ensure_sufficient_stack(|| {
+            search_graph.with_new_goal(
+                tcx,
+                canonical_input,
+                goal_evaluation,
+                |search_graph, goal_evaluation| {
+                    EvalCtxt::enter_canonical(
+                        tcx,
+                        search_graph,
+                        canonical_input,
+                        goal_evaluation,
+                        |ecx, goal| {
+                            let result = ecx.compute_goal(goal);
+                            ecx.inspect.query_result(result);
+                            result
+                        },
+                    )
+                },
+            )
+        })
     }
 
     /// Recursively evaluates `goal`, returning whether any inference vars have
@@ -329,6 +340,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
         let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
         let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, is_normalizes_to_hack);
+        let encountered_overflow = self.search_graph.encountered_overflow();
         let canonical_response = EvalCtxt::evaluate_canonical_goal(
             self.tcx(),
             self.search_graph,
@@ -377,6 +389,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             && !self.search_graph.in_cycle()
         {
             debug!("rerunning goal to check result is stable");
+            self.search_graph.reset_encountered_overflow(encountered_overflow);
             let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
             let new_canonical_response = EvalCtxt::evaluate_canonical_goal(
                 self.tcx(),
@@ -471,101 +484,22 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         let inspect = self.inspect.new_evaluate_added_goals();
         let inspect = core::mem::replace(&mut self.inspect, inspect);
 
-        let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new());
-        let mut new_goals = NestedGoals::new();
-
-        let response = self.repeat_while_none(
-            |_| Ok(Certainty::OVERFLOW),
-            |this| {
-                this.inspect.evaluate_added_goals_loop_start();
-
-                let mut has_changed = Err(Certainty::Yes);
-
-                if let Some(goal) = goals.normalizes_to_hack_goal.take() {
-                    // Replace the goal with an unconstrained infer var, so the
-                    // RHS does not affect projection candidate assembly.
-                    let unconstrained_rhs = this.next_term_infer_of_kind(goal.predicate.term);
-                    let unconstrained_goal = goal.with(
-                        this.tcx(),
-                        ty::Binder::dummy(ty::ProjectionPredicate {
-                            projection_ty: goal.predicate.projection_ty,
-                            term: unconstrained_rhs,
-                        }),
-                    );
-
-                    let (_, certainty, instantiate_goals) =
-                        match this.evaluate_goal(IsNormalizesToHack::Yes, unconstrained_goal) {
-                            Ok(r) => r,
-                            Err(NoSolution) => return Some(Err(NoSolution)),
-                        };
-                    new_goals.goals.extend(instantiate_goals);
-
-                    // Finally, equate the goal's RHS with the unconstrained var.
-                    // We put the nested goals from this into goals instead of
-                    // next_goals to avoid needing to process the loop one extra
-                    // time if this goal returns something -- I don't think this
-                    // matters in practice, though.
-                    match this.eq_and_get_goals(
-                        goal.param_env,
-                        goal.predicate.term,
-                        unconstrained_rhs,
-                    ) {
-                        Ok(eq_goals) => {
-                            goals.goals.extend(eq_goals);
-                        }
-                        Err(NoSolution) => return Some(Err(NoSolution)),
-                    };
-
-                    // We only look at the `projection_ty` part here rather than
-                    // looking at the "has changed" return from evaluate_goal,
-                    // because we expect the `unconstrained_rhs` part of the predicate
-                    // to have changed -- that means we actually normalized successfully!
-                    if goal.predicate.projection_ty
-                        != this.resolve_vars_if_possible(goal.predicate.projection_ty)
-                    {
-                        has_changed = Ok(())
-                    }
-
-                    match certainty {
-                        Certainty::Yes => {}
-                        Certainty::Maybe(_) => {
-                            // We need to resolve vars here so that we correctly
-                            // deal with `has_changed` in the next iteration.
-                            new_goals.normalizes_to_hack_goal =
-                                Some(this.resolve_vars_if_possible(goal));
-                            has_changed = has_changed.map_err(|c| c.unify_with(certainty));
-                        }
-                    }
+        let mut response = Ok(Certainty::OVERFLOW);
+        for _ in 0..self.local_overflow_limit() {
+            // FIXME: This match is a bit ugly, it might be nice to change the inspect
+            // stuff to use a closure instead. which should hopefully simplify this a bit.
+            match self.evaluate_added_goals_step() {
+                Ok(Some(cert)) => {
+                    response = Ok(cert);
+                    break;
                 }
-
-                for goal in goals.goals.drain(..) {
-                    let (changed, certainty, instantiate_goals) =
-                        match this.evaluate_goal(IsNormalizesToHack::No, goal) {
-                            Ok(result) => result,
-                            Err(NoSolution) => return Some(Err(NoSolution)),
-                        };
-                    new_goals.goals.extend(instantiate_goals);
-
-                    if changed {
-                        has_changed = Ok(());
-                    }
-
-                    match certainty {
-                        Certainty::Yes => {}
-                        Certainty::Maybe(_) => {
-                            new_goals.goals.push(goal);
-                            has_changed = has_changed.map_err(|c| c.unify_with(certainty));
-                        }
-                    }
-                }
-
-                core::mem::swap(&mut new_goals, &mut goals);
-                match has_changed {
-                    Ok(()) => None,
-                    Err(certainty) => Some(Ok(certainty)),
+                Ok(None) => {}
+                Err(NoSolution) => {
+                    response = Err(NoSolution);
+                    break;
                 }
-            },
-        );
+            }
+        }
 
         self.inspect.eval_added_goals_result(response);
 
@@ -576,9 +510,84 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         let goal_evaluations = std::mem::replace(&mut self.inspect, inspect);
         self.inspect.added_goals_evaluation(goal_evaluations);
 
-        self.nested_goals = goals;
         response
     }
+
+    /// Iterate over all added goals: returning `Ok(Some(_))` in case we can stop rerunning.
+    ///
+    /// Goals for the next step get directly added the the nested goals of the `EvalCtxt`.
+    fn evaluate_added_goals_step(&mut self) -> Result<Option<Certainty>, NoSolution> {
+        let tcx = self.tcx();
+        let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new());
+
+        self.inspect.evaluate_added_goals_loop_start();
+        // If this loop did not result in any progress, what's our final certainty.
+        let mut unchanged_certainty = Some(Certainty::Yes);
+        if let Some(goal) = goals.normalizes_to_hack_goal.take() {
+            // Replace the goal with an unconstrained infer var, so the
+            // RHS does not affect projection candidate assembly.
+            let unconstrained_rhs = self.next_term_infer_of_kind(goal.predicate.term);
+            let unconstrained_goal = goal.with(
+                tcx,
+                ty::ProjectionPredicate {
+                    projection_ty: goal.predicate.projection_ty,
+                    term: unconstrained_rhs,
+                },
+            );
+
+            let (_, certainty, instantiate_goals) =
+                self.evaluate_goal(IsNormalizesToHack::Yes, unconstrained_goal)?;
+            self.add_goals(instantiate_goals);
+
+            // Finally, equate the goal's RHS with the unconstrained var.
+            // We put the nested goals from this into goals instead of
+            // next_goals to avoid needing to process the loop one extra
+            // time if this goal returns something -- I don't think this
+            // matters in practice, though.
+            let eq_goals =
+                self.eq_and_get_goals(goal.param_env, goal.predicate.term, unconstrained_rhs)?;
+            goals.goals.extend(eq_goals);
+
+            // We only look at the `projection_ty` part here rather than
+            // looking at the "has changed" return from evaluate_goal,
+            // because we expect the `unconstrained_rhs` part of the predicate
+            // to have changed -- that means we actually normalized successfully!
+            if goal.predicate.projection_ty
+                != self.resolve_vars_if_possible(goal.predicate.projection_ty)
+            {
+                unchanged_certainty = None;
+            }
+
+            match certainty {
+                Certainty::Yes => {}
+                Certainty::Maybe(_) => {
+                    // We need to resolve vars here so that we correctly
+                    // deal with `has_changed` in the next iteration.
+                    self.set_normalizes_to_hack_goal(self.resolve_vars_if_possible(goal));
+                    unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty));
+                }
+            }
+        }
+
+        for goal in goals.goals.drain(..) {
+            let (has_changed, certainty, instantiate_goals) =
+                self.evaluate_goal(IsNormalizesToHack::No, goal)?;
+            self.add_goals(instantiate_goals);
+            if has_changed {
+                unchanged_certainty = None;
+            }
+
+            match certainty {
+                Certainty::Yes => {}
+                Certainty::Maybe(_) => {
+                    self.add_goal(goal);
+                    unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty));
+                }
+            }
+        }
+
+        Ok(unchanged_certainty)
+    }
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
@@ -593,10 +602,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         })
     }
 
-    pub(super) fn next_region_infer(&self) -> ty::Region<'tcx> {
-        self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
-    }
-
     pub(super) fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> {
         self.infcx.next_const_var(
             ty,
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 7323b98b8ce..0990b9bee90 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -10,17 +10,21 @@
 //! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
 use super::{CanonicalInput, Certainty, EvalCtxt, Goal};
 use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer};
-use crate::solve::{CanonicalResponse, QueryResult, Response};
+use crate::solve::{response_no_constraints_raw, CanonicalResponse, QueryResult, Response};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_index::IndexVec;
 use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
 use rustc_infer::infer::canonical::CanonicalVarValues;
 use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{
-    ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
+    ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
+};
+use rustc_middle::ty::{
+    self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt,
 };
-use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
 use rustc_span::DUMMY_SP;
 use std::iter;
 use std::ops::Deref;
@@ -32,6 +36,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         &self,
         goal: Goal<'tcx, T>,
     ) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx, T>) {
+        let opaque_types = self.infcx.clone_opaque_types_for_query_response();
+        let (goal, opaque_types) =
+            (goal, opaque_types).fold_with(&mut EagerResolver { infcx: self.infcx });
+
         let mut orig_values = Default::default();
         let canonical_goal = Canonicalizer::canonicalize(
             self.infcx,
@@ -40,11 +48,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             QueryInput {
                 goal,
                 anchor: self.infcx.defining_use_anchor,
-                predefined_opaques_in_body: self.tcx().mk_predefined_opaques_in_body(
-                    PredefinedOpaquesData {
-                        opaque_types: self.infcx.clone_opaque_types_for_query_response(),
-                    },
-                ),
+                predefined_opaques_in_body: self
+                    .tcx()
+                    .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }),
             },
         );
         (orig_values, canonical_goal)
@@ -70,34 +76,43 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         );
 
         let certainty = certainty.unify_with(goals_certainty);
+        if let Certainty::OVERFLOW = certainty {
+            // If we have overflow, it's probable that we're substituting a type
+            // into itself infinitely and any partial substitutions in the query
+            // response are probably not useful anyways, so just return an empty
+            // query response.
+            //
+            // This may prevent us from potentially useful inference, e.g.
+            // 2 candidates, one ambiguous and one overflow, which both
+            // have the same inference constraints.
+            //
+            // Changing this to retain some constraints in the future
+            // won't be a breaking change, so this is good enough for now.
+            return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow));
+        }
 
-        let response = match certainty {
-            Certainty::Yes | Certainty::Maybe(MaybeCause::Ambiguity) => {
-                let external_constraints = self.compute_external_query_constraints()?;
-                Response { var_values: self.var_values, external_constraints, certainty }
-            }
-            Certainty::Maybe(MaybeCause::Overflow) => {
-                // If we have overflow, it's probable that we're substituting a type
-                // into itself infinitely and any partial substitutions in the query
-                // response are probably not useful anyways, so just return an empty
-                // query response.
-                //
-                // This may prevent us from potentially useful inference, e.g.
-                // 2 candidates, one ambiguous and one overflow, which both
-                // have the same inference constraints.
-                //
-                // Changing this to retain some constraints in the future
-                // won't be a breaking change, so this is good enough for now.
-                return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow));
-            }
-        };
+        let var_values = self.var_values;
+        let external_constraints = self.compute_external_query_constraints()?;
+
+        let (var_values, mut external_constraints) =
+            (var_values, external_constraints).fold_with(&mut EagerResolver { infcx: self.infcx });
+        // Remove any trivial region constraints once we've resolved regions
+        external_constraints
+            .region_constraints
+            .outlives
+            .retain(|(outlives, _)| outlives.0.as_region().map_or(true, |re| re != outlives.1));
 
         let canonical = Canonicalizer::canonicalize(
             self.infcx,
             CanonicalizeMode::Response { max_input_universe: self.max_input_universe },
             &mut Default::default(),
-            response,
+            Response {
+                var_values,
+                certainty,
+                external_constraints: self.tcx().mk_external_constraints(external_constraints),
+            },
         );
+
         Ok(canonical)
     }
 
@@ -109,29 +124,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         &self,
         maybe_cause: MaybeCause,
     ) -> CanonicalResponse<'tcx> {
-        let unconstrained_response = Response {
-            var_values: CanonicalVarValues {
-                var_values: self.tcx().mk_args_from_iter(self.var_values.var_values.iter().map(
-                    |arg| -> ty::GenericArg<'tcx> {
-                        match arg.unpack() {
-                            GenericArgKind::Lifetime(_) => self.next_region_infer().into(),
-                            GenericArgKind::Type(_) => self.next_ty_infer().into(),
-                            GenericArgKind::Const(ct) => self.next_const_infer(ct.ty()).into(),
-                        }
-                    },
-                )),
-            },
-            external_constraints: self
-                .tcx()
-                .mk_external_constraints(ExternalConstraintsData::default()),
-            certainty: Certainty::Maybe(maybe_cause),
-        };
-
-        Canonicalizer::canonicalize(
-            self.infcx,
-            CanonicalizeMode::Response { max_input_universe: self.max_input_universe },
-            &mut Default::default(),
-            unconstrained_response,
+        response_no_constraints_raw(
+            self.tcx(),
+            self.max_input_universe,
+            self.variables,
+            Certainty::Maybe(maybe_cause),
         )
     }
 
@@ -143,7 +140,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     /// further constrained by inference, that will be passed back in the var
     /// values.
     #[instrument(level = "debug", skip(self), ret)]
-    fn compute_external_query_constraints(&self) -> Result<ExternalConstraints<'tcx>, NoSolution> {
+    fn compute_external_query_constraints(
+        &self,
+    ) -> Result<ExternalConstraintsData<'tcx>, NoSolution> {
         // We only check for leaks from universes which were entered inside
         // of the query.
         self.infcx.leak_check(self.max_input_universe, None).map_err(|e| {
@@ -173,9 +172,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
         });
 
-        Ok(self
-            .tcx()
-            .mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types }))
+        Ok(ExternalConstraintsData { region_constraints, opaque_types })
     }
 
     /// After calling a canonical query, we apply the constraints returned
@@ -333,3 +330,65 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         Ok(())
     }
 }
+
+/// Resolves ty, region, and const vars to their inferred values or their root vars.
+struct EagerResolver<'a, 'tcx> {
+    infcx: &'a InferCtxt<'tcx>,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
+    }
+
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        match *t.kind() {
+            ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
+                Ok(t) => t.fold_with(self),
+                Err(_) => Ty::new_var(self.infcx.tcx, self.infcx.root_var(vid)),
+            },
+            ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
+            ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
+            _ => {
+                if t.has_infer() {
+                    t.super_fold_with(self)
+                } else {
+                    t
+                }
+            }
+        }
+    }
+
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        match *r {
+            ty::ReVar(vid) => self
+                .infcx
+                .inner
+                .borrow_mut()
+                .unwrap_region_constraints()
+                .opportunistic_resolve_var(self.infcx.tcx, vid),
+            _ => r,
+        }
+    }
+
+    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        match c.kind() {
+            ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
+                // FIXME: we need to fold the ty too, I think.
+                match self.infcx.probe_const_var(vid) {
+                    Ok(c) => c.fold_with(self),
+                    Err(_) => {
+                        ty::Const::new_var(self.infcx.tcx, self.infcx.root_const_var(vid), c.ty())
+                    }
+                }
+            }
+            _ => {
+                if c.has_infer() {
+                    c.super_fold_with(self)
+                } else {
+                    c
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
index 4477ea7d501..317c43baf8f 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
@@ -17,6 +17,7 @@ where
 
         let mut nested_ecx = EvalCtxt {
             infcx: outer_ecx.infcx,
+            variables: outer_ecx.variables,
             var_values: outer_ecx.var_values,
             predefined_opaques_in_body: outer_ecx.predefined_opaques_in_body,
             max_input_universe: outer_ecx.max_input_universe,
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
index 8a3c7b22e32..ca4a4c9510c 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -14,7 +14,6 @@ use rustc_span::DUMMY_SP;
 use crate::solve::assembly::{Candidate, CandidateSource};
 use crate::solve::eval_ctxt::{EvalCtxt, GenerateProofTree};
 use crate::solve::inspect::ProofTreeBuilder;
-use crate::solve::search_graph::OverflowHandler;
 use crate::traits::StructurallyNormalizeExt;
 use crate::traits::TraitEngineExt;
 
@@ -143,7 +142,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         // the cycle anyways one step later.
         EvalCtxt::enter_canonical(
             self.tcx(),
-            self.search_graph(),
+            self.search_graph,
             canonical_input,
             // FIXME: This is wrong, idk if we even want to track stuff here.
             &mut ProofTreeBuilder::new_noop(),
@@ -269,7 +268,7 @@ fn rematch_unsize<'tcx>(
                 infcx.tcx,
                 ObligationCause::dummy(),
                 goal.param_env,
-                ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region)),
+                ty::OutlivesPredicate(a_ty, region),
             ));
 
             Ok(Some(ImplSource::Builtin(source, nested)))
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 63e48c94a86..63d4a38119f 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -17,10 +17,11 @@
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_infer::traits::query::NoSolution;
+use rustc_middle::infer::canonical::CanonicalVarInfos;
 use rustc_middle::traits::solve::{
     CanonicalResponse, Certainty, ExternalConstraintsData, Goal, QueryResult, Response,
 };
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex};
 use rustc_middle::ty::{
     CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
 };
@@ -284,20 +285,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     }
 }
 
-pub(super) fn response_no_constraints<'tcx>(
+fn response_no_constraints_raw<'tcx>(
     tcx: TyCtxt<'tcx>,
-    goal: Canonical<'tcx, impl Sized>,
+    max_universe: UniverseIndex,
+    variables: CanonicalVarInfos<'tcx>,
     certainty: Certainty,
-) -> QueryResult<'tcx> {
-    Ok(Canonical {
-        max_universe: goal.max_universe,
-        variables: goal.variables,
+) -> CanonicalResponse<'tcx> {
+    Canonical {
+        max_universe,
+        variables,
         value: Response {
-            var_values: CanonicalVarValues::make_identity(tcx, goal.variables),
+            var_values: CanonicalVarValues::make_identity(tcx, variables),
             // FIXME: maybe we should store the "no response" version in tcx, like
             // we do for tcx.types and stuff.
             external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()),
             certainty,
         },
-    })
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index 091b7f33834..872f0c87916 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -75,10 +75,7 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> {
             tcx,
             self.at.cause.clone(),
             self.at.param_env,
-            ty::Binder::dummy(ty::ProjectionPredicate {
-                projection_ty: alias,
-                term: new_infer_ty.into(),
-            }),
+            ty::ProjectionPredicate { projection_ty: alias, term: new_infer_ty.into() },
         );
 
         // Do not emit an error if normalization is known to fail but instead
@@ -131,10 +128,10 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> {
             tcx,
             self.at.cause.clone(),
             self.at.param_env,
-            ty::Binder::dummy(ty::ProjectionPredicate {
+            ty::ProjectionPredicate {
                 projection_ty: tcx.mk_alias_ty(uv.def, uv.args),
                 term: new_infer_ct.into(),
-            }),
+            },
         );
 
         let result = if infcx.predicate_may_hold(&obligation) {
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 2ce57751740..75cf33d8194 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -393,10 +393,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                     None => tcx.types.unit,
                     Some(field_def) => {
                         let self_ty = field_def.ty(tcx, args);
-                        ecx.add_goal(goal.with(
-                            tcx,
-                            ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
-                        ));
+                        ecx.add_goal(goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)));
                         return ecx
                             .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
                     }
@@ -406,10 +403,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                 ty::Tuple(elements) => match elements.last() {
                     None => tcx.types.unit,
                     Some(&self_ty) => {
-                        ecx.add_goal(goal.with(
-                            tcx,
-                            ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
-                        ));
+                        ecx.add_goal(goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)));
                         return ecx
                             .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
                     }
@@ -450,10 +444,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         Self::consider_implied_clause(
             ecx,
             goal,
-            ty::Binder::dummy(ty::ProjectionPredicate {
+            ty::ProjectionPredicate {
                 projection_ty: ecx.tcx().mk_alias_ty(goal.predicate.def_id(), [self_ty]),
                 term,
-            })
+            }
             .to_predicate(tcx),
             // Technically, we need to check that the future type is Sized,
             // but that's already proven by the generator being WF.
@@ -490,12 +484,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         Self::consider_implied_clause(
             ecx,
             goal,
-            ty::Binder::dummy(ty::ProjectionPredicate {
+            ty::ProjectionPredicate {
                 projection_ty: ecx
                     .tcx()
                     .mk_alias_ty(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
                 term,
-            })
+            }
             .to_predicate(tcx),
             // Technically, we need to check that the future type is Sized,
             // but that's already proven by the generator being WF.
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
index c25d6eca918..21c8d476902 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
@@ -1,37 +1,51 @@
 mod cache;
-mod overflow;
-
-pub(super) use overflow::OverflowHandler;
-use rustc_middle::traits::solve::inspect::CacheHit;
 
 use self::cache::ProvisionalEntry;
+use super::inspect::ProofTreeBuilder;
+use super::SolverMode;
 use cache::ProvisionalCache;
-use overflow::OverflowData;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_index::Idx;
 use rustc_index::IndexVec;
 use rustc_middle::dep_graph::DepKind;
+use rustc_middle::traits::solve::inspect::CacheHit;
+use rustc_middle::traits::solve::CacheData;
 use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult};
 use rustc_middle::ty::TyCtxt;
+use rustc_session::Limit;
 use std::{collections::hash_map::Entry, mem};
 
-use super::inspect::ProofTreeBuilder;
-use super::SolverMode;
-
 rustc_index::newtype_index! {
     pub struct StackDepth {}
 }
 
-struct StackElem<'tcx> {
+#[derive(Debug)]
+struct StackEntry<'tcx> {
     input: CanonicalInput<'tcx>,
+    available_depth: Limit,
+    // The maximum depth reached by this stack entry, only up-to date
+    // for the top of the stack and lazily updated for the rest.
+    reached_depth: StackDepth,
+    encountered_overflow: bool,
     has_been_used: bool,
+
+    /// We put only the root goal of a coinductive cycle into the global cache.
+    ///
+    /// If we were to use that result when later trying to prove another cycle
+    /// participant, we can end up with unstable query results.
+    ///
+    /// See tests/ui/new-solver/coinduction/incompleteness-unstable-result.rs for
+    /// an example of where this is needed.
+    cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
 }
 
 pub(super) struct SearchGraph<'tcx> {
     mode: SolverMode,
+    local_overflow_limit: usize,
     /// The stack of goals currently being computed.
     ///
     /// An element is *deeper* in the stack if its index is *lower*.
-    stack: IndexVec<StackDepth, StackElem<'tcx>>,
-    overflow_data: OverflowData,
+    stack: IndexVec<StackDepth, StackEntry<'tcx>>,
     provisional_cache: ProvisionalCache<'tcx>,
 }
 
@@ -39,8 +53,8 @@ impl<'tcx> SearchGraph<'tcx> {
     pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> {
         Self {
             mode,
+            local_overflow_limit: tcx.recursion_limit().0.ilog2() as usize,
             stack: Default::default(),
-            overflow_data: OverflowData::new(tcx),
             provisional_cache: ProvisionalCache::empty(),
         }
     }
@@ -49,15 +63,38 @@ impl<'tcx> SearchGraph<'tcx> {
         self.mode
     }
 
-    /// We do not use the global cache during coherence.
+    pub(super) fn local_overflow_limit(&self) -> usize {
+        self.local_overflow_limit
+    }
+
+    /// Update the stack and reached depths on cache hits.
+    #[instrument(level = "debug", skip(self))]
+    fn on_cache_hit(&mut self, additional_depth: usize, encountered_overflow: bool) {
+        let reached_depth = self.stack.next_index().plus(additional_depth);
+        if let Some(last) = self.stack.raw.last_mut() {
+            last.reached_depth = last.reached_depth.max(reached_depth);
+            last.encountered_overflow |= encountered_overflow;
+        }
+    }
+
+    /// Pops the highest goal from the stack, lazily updating the
+    /// the next goal in the stack.
     ///
+    /// Directly popping from the stack instead of using this method
+    /// would cause us to not track overflow and recursion depth correctly.
+    fn pop_stack(&mut self) -> StackEntry<'tcx> {
+        let elem = self.stack.pop().unwrap();
+        if let Some(last) = self.stack.raw.last_mut() {
+            last.reached_depth = last.reached_depth.max(elem.reached_depth);
+            last.encountered_overflow |= elem.encountered_overflow;
+        }
+        elem
+    }
+
     /// The trait solver behavior is different for coherence
-    /// so we would have to add the solver mode to the cache key.
-    /// This is probably not worth it as trait solving during
-    /// coherence tends to already be incredibly fast.
-    ///
-    /// We could add another global cache for coherence instead,
-    /// but that's effort so let's only do it if necessary.
+    /// so we use a separate cache. Alternatively we could use
+    /// a single cache and share it between coherence and ordinary
+    /// trait solving.
     pub(super) fn global_cache(&self, tcx: TyCtxt<'tcx>) -> &'tcx EvaluationCache<'tcx> {
         match self.mode {
             SolverMode::Normal => &tcx.new_solver_evaluation_cache,
@@ -87,36 +124,107 @@ impl<'tcx> SearchGraph<'tcx> {
         }
     }
 
-    /// Tries putting the new goal on the stack, returning an error if it is already cached.
+    /// Fetches whether the current goal encountered overflow.
+    ///
+    /// This should only be used for the check in `evaluate_goal`.
+    pub(super) fn encountered_overflow(&self) -> bool {
+        if let Some(last) = self.stack.raw.last() { last.encountered_overflow } else { false }
+    }
+
+    /// Resets `encountered_overflow` of the current goal.
+    ///
+    /// This should only be used for the check in `evaluate_goal`.
+    pub(super) fn reset_encountered_overflow(&mut self, encountered_overflow: bool) {
+        if encountered_overflow {
+            self.stack.raw.last_mut().unwrap().encountered_overflow = true;
+        }
+    }
+
+    /// Returns the remaining depth allowed for nested goals.
+    ///
+    /// This is generally simply one less than the current depth.
+    /// However, if we encountered overflow, we significantly reduce
+    /// the remaining depth of all nested goals to prevent hangs
+    /// in case there is exponential blowup.
+    fn allowed_depth_for_nested(
+        tcx: TyCtxt<'tcx>,
+        stack: &IndexVec<StackDepth, StackEntry<'tcx>>,
+    ) -> Option<Limit> {
+        if let Some(last) = stack.raw.last() {
+            if last.available_depth.0 == 0 {
+                return None;
+            }
+
+            Some(if last.encountered_overflow {
+                Limit(last.available_depth.0 / 4)
+            } else {
+                Limit(last.available_depth.0 - 1)
+            })
+        } else {
+            Some(tcx.recursion_limit())
+        }
+    }
+
+    /// Probably the most involved method of the whole solver.
     ///
-    /// This correctly updates the provisional cache if there is a cycle.
-    #[instrument(level = "debug", skip(self, tcx, inspect), ret)]
-    fn try_push_stack(
+    /// Given some goal which is proven via the `prove_goal` closure, this
+    /// handles caching, overflow, and coinductive cycles.
+    pub(super) fn with_new_goal(
         &mut self,
         tcx: TyCtxt<'tcx>,
         input: CanonicalInput<'tcx>,
         inspect: &mut ProofTreeBuilder<'tcx>,
-    ) -> Result<(), QueryResult<'tcx>> {
-        // Look at the provisional cache to check for cycles.
+        mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>,
+    ) -> QueryResult<'tcx> {
+        // Check for overflow.
+        let Some(available_depth) = Self::allowed_depth_for_nested(tcx, &self.stack) else {
+            if let Some(last) = self.stack.raw.last_mut() {
+                last.encountered_overflow = true;
+            }
+            return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW);
+        };
+
+        // Try to fetch the goal from the global cache.
+        if inspect.use_global_cache() {
+            if let Some(CacheData { result, reached_depth, encountered_overflow }) =
+                self.global_cache(tcx).get(
+                    tcx,
+                    input,
+                    |cycle_participants| {
+                        self.stack.iter().any(|entry| cycle_participants.contains(&entry.input))
+                    },
+                    available_depth,
+                )
+            {
+                self.on_cache_hit(reached_depth, encountered_overflow);
+                return result;
+            }
+        }
+
+        // Look at the provisional cache to detect cycles.
         let cache = &mut self.provisional_cache;
         match cache.lookup_table.entry(input) {
-            // No entry, simply push this goal on the stack after dealing with overflow.
+            // No entry, we push this goal on the stack and try to prove it.
             Entry::Vacant(v) => {
-                if self.overflow_data.has_overflow(self.stack.len()) {
-                    return Err(self.deal_with_overflow(tcx, input));
-                }
-
-                let depth = self.stack.push(StackElem { input, has_been_used: false });
-                let response = super::response_no_constraints(tcx, input, Certainty::Yes);
+                let depth = self.stack.next_index();
+                let entry = StackEntry {
+                    input,
+                    available_depth,
+                    reached_depth: depth,
+                    encountered_overflow: false,
+                    has_been_used: false,
+                    cycle_participants: Default::default(),
+                };
+                assert_eq!(self.stack.push(entry), depth);
+                let response = Self::response_no_constraints(tcx, input, Certainty::Yes);
                 let entry_index = cache.entries.push(ProvisionalEntry { response, depth, input });
                 v.insert(entry_index);
-                Ok(())
             }
             // We have a nested goal which relies on a goal `root` deeper in the stack.
             //
-            // We first store that we may have to rerun `evaluate_goal` for `root` in case the
-            // provisional response is not equal to the final response. We also update the depth
-            // of all goals which recursively depend on our current goal to depend on `root`
+            // We first store that we may have to reprove `root` in case the provisional
+            // response is not equal to the final response. We also update the depth of all
+            // goals which recursively depend on our current goal to depend on `root`
             // instead.
             //
             // Finally we can return either the provisional response for that goal if we have a
@@ -125,13 +233,16 @@ impl<'tcx> SearchGraph<'tcx> {
                 inspect.cache_hit(CacheHit::Provisional);
 
                 let entry_index = *entry_index.get();
-
                 let stack_depth = cache.depth(entry_index);
                 debug!("encountered cycle with depth {stack_depth:?}");
 
                 cache.add_dependency_of_leaf_on(entry_index);
+                let mut iter = self.stack.iter_mut();
+                let root = iter.nth(stack_depth.as_usize()).unwrap();
+                for e in iter {
+                    root.cycle_participants.insert(e.input);
+                }
 
-                self.stack[stack_depth].has_been_used = true;
                 // NOTE: The goals on the stack aren't the only goals involved in this cycle.
                 // We can also depend on goals which aren't part of the stack but coinductively
                 // depend on the stack themselves. We already checked whether all the goals
@@ -142,145 +253,111 @@ impl<'tcx> SearchGraph<'tcx> {
                     .iter()
                     .all(|g| g.input.value.goal.predicate.is_coinductive(tcx))
                 {
-                    Err(cache.provisional_result(entry_index))
+                    // If we're in a coinductive cycle, we have to retry proving the current goal
+                    // until we reach a fixpoint.
+                    self.stack[stack_depth].has_been_used = true;
+                    return cache.provisional_result(entry_index);
                 } else {
-                    Err(super::response_no_constraints(tcx, input, Certainty::OVERFLOW))
+                    return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW);
                 }
             }
         }
-    }
 
-    /// We cannot simply store the result of [super::EvalCtxt::compute_goal] as we have to deal with
-    /// coinductive cycles.
-    ///
-    /// When we encounter a coinductive cycle, we have to prove the final result of that cycle
-    /// while we are still computing that result. Because of this we continuously recompute the
-    /// cycle until the result of the previous iteration is equal to the final result, at which
-    /// point we are done.
-    ///
-    /// This function returns `true` if we were able to finalize the goal and `false` if it has
-    /// updated the provisional cache and we have to recompute the current goal.
-    ///
-    /// FIXME: Refer to the rustc-dev-guide entry once it exists.
-    #[instrument(level = "debug", skip(self, actual_input), ret)]
-    fn try_finalize_goal(
-        &mut self,
-        actual_input: CanonicalInput<'tcx>,
-        response: QueryResult<'tcx>,
-    ) -> bool {
-        let stack_elem = self.stack.pop().unwrap();
-        let StackElem { input, has_been_used } = stack_elem;
-        assert_eq!(input, actual_input);
+        // This is for global caching, so we properly track query dependencies.
+        // Everything that affects the `result` should be performed within this
+        // `with_anon_task` closure.
+        let ((final_entry, result), dep_node) =
+            tcx.dep_graph.with_anon_task(tcx, DepKind::TraitSelect, || {
+                // When we encounter a coinductive cycle, we have to fetch the
+                // result of that cycle while we are still computing it. Because
+                // of this we continuously recompute the cycle until the result
+                // of the previous iteration is equal to the final result, at which
+                // point we are done.
+                for _ in 0..self.local_overflow_limit() {
+                    let response = prove_goal(self, inspect);
 
-        let cache = &mut self.provisional_cache;
-        let provisional_entry_index = *cache.lookup_table.get(&input).unwrap();
-        let provisional_entry = &mut cache.entries[provisional_entry_index];
-        // We eagerly update the response in the cache here. If we have to reevaluate
-        // this goal we use the new response when hitting a cycle, and we definitely
-        // want to access the final response whenever we look at the cache.
-        let prev_response = mem::replace(&mut provisional_entry.response, response);
-
-        // Was the current goal the root of a cycle and was the provisional response
-        // different from the final one.
-        if has_been_used && prev_response != response {
-            // If so, remove all entries whose result depends on this goal
-            // from the provisional cache...
-            //
-            // That's not completely correct, as a nested goal can also
-            // depend on a goal which is lower in the stack so it doesn't
-            // actually depend on the current goal. This should be fairly
-            // rare and is hopefully not relevant for performance.
-            #[allow(rustc::potential_query_instability)]
-            cache.lookup_table.retain(|_key, index| *index <= provisional_entry_index);
-            cache.entries.truncate(provisional_entry_index.index() + 1);
-
-            // ...and finally push our goal back on the stack and reevaluate it.
-            self.stack.push(StackElem { input, has_been_used: false });
-            false
-        } else {
-            true
-        }
-    }
+                    // Check whether the current goal is the root of a cycle and whether
+                    // we have to rerun because its provisional result differed from the
+                    // final result.
+                    //
+                    // Also update the response for this goal stored in the provisional
+                    // cache.
+                    let stack_entry = self.pop_stack();
+                    debug_assert_eq!(stack_entry.input, input);
+                    let cache = &mut self.provisional_cache;
+                    let provisional_entry_index =
+                        *cache.lookup_table.get(&stack_entry.input).unwrap();
+                    let provisional_entry = &mut cache.entries[provisional_entry_index];
+                    let prev_response = mem::replace(&mut provisional_entry.response, response);
+                    if stack_entry.has_been_used && prev_response != response {
+                        // If so, remove all entries whose result depends on this goal
+                        // from the provisional cache...
+                        //
+                        // That's not completely correct, as a nested goal can also
+                        // depend on a goal which is lower in the stack so it doesn't
+                        // actually depend on the current goal. This should be fairly
+                        // rare and is hopefully not relevant for performance.
+                        #[allow(rustc::potential_query_instability)]
+                        cache.lookup_table.retain(|_key, index| *index <= provisional_entry_index);
+                        cache.entries.truncate(provisional_entry_index.index() + 1);
 
-    pub(super) fn with_new_goal(
-        &mut self,
-        tcx: TyCtxt<'tcx>,
-        canonical_input: CanonicalInput<'tcx>,
-        inspect: &mut ProofTreeBuilder<'tcx>,
-        mut loop_body: impl FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>,
-    ) -> QueryResult<'tcx> {
-        if inspect.use_global_cache() {
-            if let Some(result) = self.global_cache(tcx).get(&canonical_input, tcx) {
-                debug!(?canonical_input, ?result, "cache hit");
-                inspect.cache_hit(CacheHit::Global);
-                return result;
-            }
-        }
+                        // ...and finally push our goal back on the stack and reevaluate it.
+                        self.stack.push(StackEntry { has_been_used: false, ..stack_entry });
+                    } else {
+                        return (stack_entry, response);
+                    }
+                }
 
-        match self.try_push_stack(tcx, canonical_input, inspect) {
-            Ok(()) => {}
-            // Our goal is already on the stack, eager return.
-            Err(response) => return response,
-        }
-
-        // This is for global caching, so we properly track query dependencies.
-        // Everything that affects the `Result` should be performed within this
-        // `with_anon_task` closure.
-        let (result, dep_node) = tcx.dep_graph.with_anon_task(tcx, DepKind::TraitSelect, || {
-            self.repeat_while_none(
-                |this| {
-                    let result = this.deal_with_overflow(tcx, canonical_input);
-                    let _ = this.stack.pop().unwrap();
-                    result
-                },
-                |this| {
-                    let result = loop_body(this, inspect);
-                    this.try_finalize_goal(canonical_input, result).then(|| result)
-                },
-            )
-        });
+                debug!("canonical cycle overflow");
+                let current_entry = self.pop_stack();
+                let result = Self::response_no_constraints(tcx, input, Certainty::OVERFLOW);
+                (current_entry, result)
+            });
 
+        // We're now done with this goal. In case this goal is involved in a larger cycle
+        // do not remove it from the provisional cache and do not add it to the global
+        // cache.
+        //
+        // It is not possible for any nested goal to depend on something deeper on the
+        // stack, as this would have also updated the depth of the current goal.
         let cache = &mut self.provisional_cache;
-        let provisional_entry_index = *cache.lookup_table.get(&canonical_input).unwrap();
+        let provisional_entry_index = *cache.lookup_table.get(&input).unwrap();
         let provisional_entry = &mut cache.entries[provisional_entry_index];
         let depth = provisional_entry.depth;
-
-        // If not, we're done with this goal.
-        //
-        // Check whether that this goal doesn't depend on a goal deeper on the stack
-        // and if so, move it to the global cache.
-        //
-        // Note that if any nested goal were to depend on something deeper on the stack,
-        // this would have also updated the depth of the current goal.
         if depth == self.stack.next_index() {
-            // If the current goal is the head of a cycle, we drop all other
-            // cycle participants without moving them to the global cache.
-            let other_cycle_participants = provisional_entry_index.index() + 1;
-            for (i, entry) in cache.entries.drain_enumerated(other_cycle_participants..) {
+            for (i, entry) in cache.entries.drain_enumerated(provisional_entry_index.index()..) {
                 let actual_index = cache.lookup_table.remove(&entry.input);
                 debug_assert_eq!(Some(i), actual_index);
                 debug_assert!(entry.depth == depth);
             }
 
-            let current_goal = cache.entries.pop().unwrap();
-            let actual_index = cache.lookup_table.remove(&current_goal.input);
-            debug_assert_eq!(Some(provisional_entry_index), actual_index);
-            debug_assert!(current_goal.depth == depth);
-
-            // We move the root goal to the global cache if we either did not hit an overflow or if it's
-            // the root goal as that will now always hit the same overflow limit.
-            //
-            // NOTE: We cannot move any non-root goals to the global cache. When replaying the root goal's
-            // dependencies, our non-root goal may no longer appear as child of the root goal.
+            // When encountering a cycle, both inductive and coinductive, we only
+            // move the root into the global cache. We also store all other cycle
+            // participants involved.
             //
-            // See https://github.com/rust-lang/rust/pull/108071 for some additional context.
-            let can_cache = inspect.use_global_cache()
-                && (!self.overflow_data.did_overflow() || self.stack.is_empty());
-            if can_cache {
-                self.global_cache(tcx).insert(current_goal.input, dep_node, current_goal.response)
-            }
+            // We disable the global cache entry of the root goal if a cycle
+            // participant is on the stack. This is necessary to prevent unstable
+            // results. See the comment of `StackEntry::cycle_participants` for
+            // more details.
+            let reached_depth = final_entry.reached_depth.as_usize() - self.stack.len();
+            self.global_cache(tcx).insert(
+                input,
+                reached_depth,
+                final_entry.encountered_overflow,
+                final_entry.cycle_participants,
+                dep_node,
+                result,
+            )
         }
 
         result
     }
+
+    fn response_no_constraints(
+        tcx: TyCtxt<'tcx>,
+        goal: CanonicalInput<'tcx>,
+        certainty: Certainty,
+    ) -> QueryResult<'tcx> {
+        Ok(super::response_no_constraints_raw(tcx, goal.max_universe, goal.variables, certainty))
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs b/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs
deleted file mode 100644
index 83a051eeb1a..00000000000
--- a/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use rustc_infer::infer::canonical::Canonical;
-use rustc_infer::traits::query::NoSolution;
-use rustc_middle::traits::solve::{Certainty, QueryResult};
-use rustc_middle::ty::TyCtxt;
-use rustc_session::Limit;
-
-use super::SearchGraph;
-use crate::solve::{response_no_constraints, EvalCtxt};
-
-/// When detecting a solver overflow, we return ambiguity. Overflow can be
-/// *hidden* by either a fatal error in an **AND** or a trivial success in an **OR**.
-///
-/// This is in issue in case of exponential blowup, e.g. if each goal on the stack
-/// has multiple nested (overflowing) candidates. To deal with this, we reduce the limit
-/// used by the solver when hitting the default limit for the first time.
-///
-/// FIXME: Get tests where always using the `default_limit` results in a hang and refer
-/// to them here. We can also improve the overflow strategy if necessary.
-pub(super) struct OverflowData {
-    default_limit: Limit,
-    current_limit: Limit,
-    /// When proving an **AND** we have to repeatedly iterate over the yet unproven goals.
-    ///
-    /// Because of this each iteration also increases the depth in addition to the stack
-    /// depth.
-    additional_depth: usize,
-}
-
-impl OverflowData {
-    pub(super) fn new(tcx: TyCtxt<'_>) -> OverflowData {
-        let default_limit = tcx.recursion_limit();
-        OverflowData { default_limit, current_limit: default_limit, additional_depth: 0 }
-    }
-
-    #[inline]
-    pub(super) fn did_overflow(&self) -> bool {
-        self.default_limit.0 != self.current_limit.0
-    }
-
-    #[inline]
-    pub(super) fn has_overflow(&self, depth: usize) -> bool {
-        !self.current_limit.value_within_limit(depth + self.additional_depth)
-    }
-
-    /// Updating the current limit when hitting overflow.
-    fn deal_with_overflow(&mut self) {
-        // When first hitting overflow we reduce the overflow limit
-        // for all future goals to prevent hangs if there's an exponential
-        // blowup.
-        self.current_limit.0 = self.default_limit.0 / 8;
-    }
-}
-
-pub(in crate::solve) trait OverflowHandler<'tcx> {
-    fn search_graph(&mut self) -> &mut SearchGraph<'tcx>;
-
-    fn repeat_while_none<T>(
-        &mut self,
-        on_overflow: impl FnOnce(&mut Self) -> Result<T, NoSolution>,
-        mut loop_body: impl FnMut(&mut Self) -> Option<Result<T, NoSolution>>,
-    ) -> Result<T, NoSolution> {
-        let start_depth = self.search_graph().overflow_data.additional_depth;
-        let depth = self.search_graph().stack.len();
-        while !self.search_graph().overflow_data.has_overflow(depth) {
-            if let Some(result) = loop_body(self) {
-                self.search_graph().overflow_data.additional_depth = start_depth;
-                return result;
-            }
-
-            self.search_graph().overflow_data.additional_depth += 1;
-        }
-        self.search_graph().overflow_data.additional_depth = start_depth;
-        self.search_graph().overflow_data.deal_with_overflow();
-        on_overflow(self)
-    }
-
-    // Increment the `additional_depth` by one and evaluate `body`, or `on_overflow`
-    // if the depth is overflown.
-    fn with_incremented_depth<T>(
-        &mut self,
-        on_overflow: impl FnOnce(&mut Self) -> T,
-        body: impl FnOnce(&mut Self) -> T,
-    ) -> T {
-        let depth = self.search_graph().stack.len();
-        self.search_graph().overflow_data.additional_depth += 1;
-
-        let result = if self.search_graph().overflow_data.has_overflow(depth) {
-            self.search_graph().overflow_data.deal_with_overflow();
-            on_overflow(self)
-        } else {
-            body(self)
-        };
-
-        self.search_graph().overflow_data.additional_depth -= 1;
-        result
-    }
-}
-
-impl<'tcx> OverflowHandler<'tcx> for EvalCtxt<'_, 'tcx> {
-    fn search_graph(&mut self) -> &mut SearchGraph<'tcx> {
-        &mut self.search_graph
-    }
-}
-
-impl<'tcx> OverflowHandler<'tcx> for SearchGraph<'tcx> {
-    fn search_graph(&mut self) -> &mut SearchGraph<'tcx> {
-        self
-    }
-}
-
-impl<'tcx> SearchGraph<'tcx> {
-    pub fn deal_with_overflow(
-        &mut self,
-        tcx: TyCtxt<'tcx>,
-        goal: Canonical<'tcx, impl Sized>,
-    ) -> QueryResult<'tcx> {
-        self.overflow_data.deal_with_overflow();
-        response_no_constraints(tcx, goal, Certainty::OVERFLOW)
-    }
-}
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 14a5b9656e5..db80b62d8a2 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -1,7 +1,6 @@
 //! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
 
 use super::assembly::{self, structural_traits};
-use super::search_graph::OverflowHandler;
 use super::{EvalCtxt, SolverMode};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{LangItem, Movability};
@@ -444,7 +443,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             Err(NoSolution) => vec![],
         };
 
-        ecx.probe(|_| CandidateKind::DynUpcastingAssembly).enter(|ecx| {
+        ecx.probe(|_| CandidateKind::UnsizeAssembly).enter(|ecx| {
             let a_ty = goal.predicate.self_ty();
             // We need to normalize the b_ty since it's matched structurally
             // in the other functions below.
@@ -526,7 +525,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         b_region: ty::Region<'tcx>,
     ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
         let tcx = self.tcx();
-        let Goal { predicate: (a_ty, b_ty), .. } = goal;
+        let Goal { predicate: (a_ty, _b_ty), .. } = goal;
 
         // All of a's auto traits need to be in b's auto traits.
         let auto_traits_compatible =
@@ -535,51 +534,30 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             return vec![];
         }
 
-        // Try to match `a_ty` against `b_ty`, replacing `a_ty`'s principal trait ref with
-        // the supertrait principal and subtyping the types.
-        let unsize_dyn_to_principal =
-            |ecx: &mut Self, principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
-                ecx.probe_candidate("upcast dyn to principle").enter(
-                    |ecx| -> Result<_, NoSolution> {
-                        // Require that all of the trait predicates from A match B, except for
-                        // the auto traits. We do this by constructing a new A type with B's
-                        // auto traits, and equating these types.
-                        let new_a_data = principal
-                            .into_iter()
-                            .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait))
-                            .chain(a_data.iter().filter(|a| {
-                                matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_))
-                            }))
-                            .chain(
-                                b_data
-                                    .auto_traits()
-                                    .map(ty::ExistentialPredicate::AutoTrait)
-                                    .map(ty::Binder::dummy),
-                            );
-                        let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data);
-                        let new_a_ty = Ty::new_dynamic(tcx, new_a_data, b_region, ty::Dyn);
-
-                        // We also require that A's lifetime outlives B's lifetime.
-                        ecx.eq(goal.param_env, new_a_ty, b_ty)?;
-                        ecx.add_goal(goal.with(tcx, ty::OutlivesPredicate(a_region, b_region)));
-                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                    },
-                )
-            };
-
         let mut responses = vec![];
         // If the principal def ids match (or are both none), then we're not doing
         // trait upcasting. We're just removing auto traits (or shortening the lifetime).
         if a_data.principal_def_id() == b_data.principal_def_id() {
-            if let Ok(resp) = unsize_dyn_to_principal(self, a_data.principal()) {
+            if let Ok(resp) = self.consider_builtin_upcast_to_principal(
+                goal,
+                a_data,
+                a_region,
+                b_data,
+                b_region,
+                a_data.principal(),
+            ) {
                 responses.push((resp, BuiltinImplSource::Misc));
             }
         } else if let Some(a_principal) = a_data.principal() {
             self.walk_vtable(
                 a_principal.with_self_ty(tcx, a_ty),
                 |ecx, new_a_principal, _, vtable_vptr_slot| {
-                    if let Ok(resp) = unsize_dyn_to_principal(
-                        ecx,
+                    if let Ok(resp) = ecx.consider_builtin_upcast_to_principal(
+                        goal,
+                        a_data,
+                        a_region,
+                        b_data,
+                        b_region,
                         Some(new_a_principal.map_bound(|trait_ref| {
                             ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
                         })),
@@ -631,6 +609,83 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 
+    fn consider_builtin_upcast_to_principal(
+        &mut self,
+        goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
+        a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+        a_region: ty::Region<'tcx>,
+        b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+        b_region: ty::Region<'tcx>,
+        upcast_principal: Option<ty::PolyExistentialTraitRef<'tcx>>,
+    ) -> QueryResult<'tcx> {
+        let param_env = goal.param_env;
+
+        // More than one projection in a_ty's bounds may match the projection
+        // in b_ty's bound. Use this to first determine *which* apply without
+        // having any inference side-effects. We process obligations because
+        // unification may initially succeed due to deferred projection equality.
+        let projection_may_match =
+            |ecx: &mut Self,
+             source_projection: ty::PolyExistentialProjection<'tcx>,
+             target_projection: ty::PolyExistentialProjection<'tcx>| {
+                source_projection.item_def_id() == target_projection.item_def_id()
+                    && ecx
+                        .probe(|_| CandidateKind::UpcastProbe)
+                        .enter(|ecx| -> Result<(), NoSolution> {
+                            ecx.eq(param_env, source_projection, target_projection)?;
+                            let _ = ecx.try_evaluate_added_goals()?;
+                            Ok(())
+                        })
+                        .is_ok()
+            };
+
+        for bound in b_data {
+            match bound.skip_binder() {
+                // Check that a's supertrait (upcast_principal) is compatible
+                // with the target (b_ty).
+                ty::ExistentialPredicate::Trait(target_principal) => {
+                    self.eq(param_env, upcast_principal.unwrap(), bound.rebind(target_principal))?;
+                }
+                // Check that b_ty's projection is satisfied by exactly one of
+                // a_ty's projections. First, we look through the list to see if
+                // any match. If not, error. Then, if *more* than one matches, we
+                // return ambiguity. Otherwise, if exactly one matches, equate
+                // it with b_ty's projection.
+                ty::ExistentialPredicate::Projection(target_projection) => {
+                    let target_projection = bound.rebind(target_projection);
+                    let mut matching_projections =
+                        a_data.projection_bounds().filter(|source_projection| {
+                            projection_may_match(self, *source_projection, target_projection)
+                        });
+                    let Some(source_projection) = matching_projections.next() else {
+                        return Err(NoSolution);
+                    };
+                    if matching_projections.next().is_some() {
+                        return self.evaluate_added_goals_and_make_canonical_response(
+                            Certainty::AMBIGUOUS,
+                        );
+                    }
+                    self.eq(param_env, source_projection, target_projection)?;
+                }
+                // Check that b_ty's auto traits are present in a_ty's bounds.
+                ty::ExistentialPredicate::AutoTrait(def_id) => {
+                    if !a_data.auto_traits().any(|source_def_id| source_def_id == def_id) {
+                        return Err(NoSolution);
+                    }
+                }
+            }
+        }
+
+        // Also require that a_ty's lifetime outlives b_ty's lifetime.
+        self.add_goal(Goal::new(
+            self.tcx(),
+            param_env,
+            ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
+        ));
+
+        self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+    }
+
     /// We have the following builtin impls for arrays:
     /// ```ignore (builtin impl example)
     /// impl<T: ?Sized, const N: usize> Unsize<[T]> for [T; N] {}
@@ -857,12 +912,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             ecx.add_goals(
                 constituent_tys(ecx, goal.predicate.self_ty())?
                     .into_iter()
-                    .map(|ty| {
-                        goal.with(
-                            ecx.tcx(),
-                            ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)),
-                        )
-                    })
+                    .map(|ty| goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty)))
                     .collect::<Vec<_>>(),
             );
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
@@ -879,7 +929,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     }
 
     /// Normalize a non-self type when it is structually matched on when solving
-    /// a built-in goal. This is handled already through `assemble_candidates_after_normalizing_self_ty`
+    /// a built-in goal.
+    ///
+    /// This is handled already through `assemble_candidates_after_normalizing_self_ty`
     /// for the self type, but for other goals, additional normalization of other
     /// arguments may be needed to completely implement the semantics of the trait.
     ///
@@ -894,30 +946,22 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             return Ok(Some(ty));
         }
 
-        self.repeat_while_none(
-            |_| Ok(None),
-            |ecx| {
-                let ty::Alias(_, projection_ty) = *ty.kind() else {
-                    return Some(Ok(Some(ty)));
-                };
-
-                let normalized_ty = ecx.next_ty_infer();
-                let normalizes_to_goal = Goal::new(
-                    ecx.tcx(),
-                    param_env,
-                    ty::Binder::dummy(ty::ProjectionPredicate {
-                        projection_ty,
-                        term: normalized_ty.into(),
-                    }),
-                );
-                ecx.add_goal(normalizes_to_goal);
-                if let Err(err) = ecx.try_evaluate_added_goals() {
-                    return Some(Err(err));
-                }
+        for _ in 0..self.local_overflow_limit() {
+            let ty::Alias(_, projection_ty) = *ty.kind() else {
+                return Ok(Some(ty));
+            };
 
-                ty = ecx.resolve_vars_if_possible(normalized_ty);
-                None
-            },
-        )
+            let normalized_ty = self.next_ty_infer();
+            let normalizes_to_goal = Goal::new(
+                self.tcx(),
+                param_env,
+                ty::ProjectionPredicate { projection_ty, term: normalized_ty.into() },
+            );
+            self.add_goal(normalizes_to_goal);
+            self.try_evaluate_added_goals()?;
+            ty = self.resolve_vars_if_possible(normalized_ty);
+        }
+
+        Ok(None)
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index eae13eb6302..4d85e2b6089 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2987,6 +2987,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         unsatisfied_const: bool,
     ) {
         let body_def_id = obligation.cause.body_id;
+        let span = if let ObligationCauseCode::BinOp { rhs_span: Some(rhs_span), .. } =
+            obligation.cause.code()
+        {
+            *rhs_span
+        } else {
+            span
+        };
+
         // Try to report a help message
         if is_fn_trait
             && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 46c31c77613..1c59f3ff6c7 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -2789,7 +2789,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             // implement this trait and list them.
                             err.note(format!(
                                 "`{short_item_name}` is a \"sealed trait\", because to implement \
-                                 it you also need to implelement `{}`, which is not accessible; \
+                                 it you also need to implement `{}`, which is not accessible; \
                                  this is usually done to force you to use one of the provided \
                                  types that already implement it",
                                 with_no_trimmed_paths!(tcx.def_path_str(def_id)),
@@ -2854,7 +2854,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         err.note("all local variables must have a statically known size");
                     }
                     Some(Node::Local(hir::Local {
-                        init: Some(hir::Expr { kind: hir::ExprKind::Index(_, _), span, .. }),
+                        init: Some(hir::Expr { kind: hir::ExprKind::Index(..), span, .. }),
                         ..
                     })) => {
                         // When encountering an assignment of an unsized trait, like
@@ -3953,9 +3953,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         candidate_impls: &[ImplCandidate<'tcx>],
         span: Span,
     ) {
-        // We can only suggest the slice coersion for function arguments since the suggestion
-        // would make no sense in turbofish or call
-        let ObligationCauseCode::FunctionArgumentObligation { .. } = obligation.cause.code() else {
+        // We can only suggest the slice coersion for function and binary operation arguments,
+        // since the suggestion would make no sense in turbofish or call
+        let (ObligationCauseCode::BinOp { .. }
+        | ObligationCauseCode::FunctionArgumentObligation { .. }) = obligation.cause.code()
+        else {
             return;
         };
 
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 8f2f02a5e41..e3da87a2210 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -745,7 +745,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         match (source.kind(), target.kind()) {
             // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
-            (&ty::Dynamic(ref data_a, _, ty::Dyn), &ty::Dynamic(ref data_b, _, ty::Dyn)) => {
+            (
+                &ty::Dynamic(ref a_data, a_region, ty::Dyn),
+                &ty::Dynamic(ref b_data, b_region, ty::Dyn),
+            ) => {
                 // Upcast coercions permit several things:
                 //
                 // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
@@ -757,19 +760,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 //
                 // We always perform upcasting coercions when we can because of reason
                 // #2 (region bounds).
-                let auto_traits_compatible = data_b
+                let auto_traits_compatible = b_data
                     .auto_traits()
                     // All of a's auto traits need to be in b's auto traits.
-                    .all(|b| data_a.auto_traits().any(|a| a == b));
+                    .all(|b| a_data.auto_traits().any(|a| a == b));
                 if auto_traits_compatible {
-                    let principal_def_id_a = data_a.principal_def_id();
-                    let principal_def_id_b = data_b.principal_def_id();
+                    let principal_def_id_a = a_data.principal_def_id();
+                    let principal_def_id_b = b_data.principal_def_id();
                     if principal_def_id_a == principal_def_id_b {
                         // no cyclic
                         candidates.vec.push(BuiltinUnsizeCandidate);
                     } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() {
                         // not casual unsizing, now check whether this is trait upcasting coercion.
-                        let principal_a = data_a.principal().unwrap();
+                        let principal_a = a_data.principal().unwrap();
                         let target_trait_did = principal_def_id_b.unwrap();
                         let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
                         if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object(
@@ -785,9 +788,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         for (idx, upcast_trait_ref) in
                             util::supertraits(self.tcx(), source_trait_ref).enumerate()
                         {
-                            if upcast_trait_ref.def_id() == target_trait_did {
-                                candidates.vec.push(TraitUpcastingUnsizeCandidate(idx));
-                            }
+                            self.infcx.probe(|_| {
+                                if upcast_trait_ref.def_id() == target_trait_did
+                                    && let Ok(nested) = self.match_upcast_principal(
+                                        obligation,
+                                        upcast_trait_ref,
+                                        a_data,
+                                        b_data,
+                                        a_region,
+                                        b_region,
+                                    )
+                                {
+                                    if nested.is_none() {
+                                        candidates.ambiguous = true;
+                                    }
+                                    candidates.vec.push(TraitUpcastingUnsizeCandidate(idx));
+                                }
+                            })
                         }
                     }
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index cf9d2bda17e..71a82baeec6 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -879,68 +879,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         // `assemble_candidates_for_unsizing` should ensure there are no late-bound
         // regions here. See the comment there for more details.
-        let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
-        let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1);
-        let target = self.infcx.shallow_resolve(target);
-
-        debug!(?source, ?target, "confirm_trait_upcasting_unsize_candidate");
-
-        let mut nested = vec![];
-        let source_trait_ref;
-        let upcast_trait_ref;
-        match (source.kind(), target.kind()) {
-            // TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion).
-            (
-                &ty::Dynamic(ref data_a, r_a, repr_a @ ty::Dyn),
-                &ty::Dynamic(ref data_b, r_b, ty::Dyn),
-            ) => {
-                // See `assemble_candidates_for_unsizing` for more info.
-                // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
-                let principal_a = data_a.principal().unwrap();
-                source_trait_ref = principal_a.with_self_ty(tcx, source);
-                upcast_trait_ref = util::supertraits(tcx, source_trait_ref).nth(idx).unwrap();
-                assert_eq!(data_b.principal_def_id(), Some(upcast_trait_ref.def_id()));
-                let existential_predicate = upcast_trait_ref.map_bound(|trait_ref| {
-                    ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
-                        tcx, trait_ref,
-                    ))
-                });
-                let iter = Some(existential_predicate)
-                    .into_iter()
-                    .chain(
-                        data_a
-                            .projection_bounds()
-                            .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)),
-                    )
-                    .chain(
-                        data_b
-                            .auto_traits()
-                            .map(ty::ExistentialPredicate::AutoTrait)
-                            .map(ty::Binder::dummy),
-                    );
-                let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter);
-                let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b, repr_a);
-
-                // Require that the traits involved in this upcast are **equal**;
-                // only the **lifetime bound** is changed.
-                let InferOk { obligations, .. } = self
-                    .infcx
-                    .at(&obligation.cause, obligation.param_env)
-                    .sup(DefineOpaqueTypes::No, target, source_trait)
-                    .map_err(|_| Unimplemented)?;
-                nested.extend(obligations);
-
-                let outlives = ty::OutlivesPredicate(r_a, r_b);
-                nested.push(Obligation::with_depth(
-                    tcx,
-                    obligation.cause.clone(),
-                    obligation.recursion_depth + 1,
-                    obligation.param_env,
-                    obligation.predicate.rebind(outlives),
-                ));
-            }
-            _ => bug!(),
-        };
+        let predicate = obligation.predicate.no_bound_vars().unwrap();
+        let a_ty = self.infcx.shallow_resolve(predicate.self_ty());
+        let b_ty = self.infcx.shallow_resolve(predicate.trait_ref.args.type_at(1));
+
+        let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else { bug!() };
+        let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else { bug!() };
+
+        let source_principal = a_data.principal().unwrap().with_self_ty(tcx, a_ty);
+        let unnormalized_upcast_principal =
+            util::supertraits(tcx, source_principal).nth(idx).unwrap();
+
+        let nested = self
+            .match_upcast_principal(
+                obligation,
+                unnormalized_upcast_principal,
+                a_data,
+                b_data,
+                a_region,
+                b_region,
+            )?
+            .expect("did not expect ambiguity during confirmation");
 
         let vtable_segment_callback = {
             let mut vptr_offset = 0;
@@ -951,7 +910,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
                     VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
                         vptr_offset += count_own_vtable_entries(tcx, trait_ref);
-                        if trait_ref == upcast_trait_ref {
+                        if trait_ref == unnormalized_upcast_principal {
                             if emit_vptr {
                                 return ControlFlow::Break(Some(vptr_offset));
                             } else {
@@ -969,7 +928,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         };
 
         let vtable_vptr_slot =
-            prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback).unwrap();
+            prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap();
 
         Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, nested))
     }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 5da8d838db2..f1bd9f8b71a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2477,6 +2477,98 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         Ok(Normalized { value: impl_args, obligations: nested_obligations })
     }
 
+    fn match_upcast_principal(
+        &mut self,
+        obligation: &PolyTraitObligation<'tcx>,
+        unnormalized_upcast_principal: ty::PolyTraitRef<'tcx>,
+        a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+        b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+        a_region: ty::Region<'tcx>,
+        b_region: ty::Region<'tcx>,
+    ) -> SelectionResult<'tcx, Vec<PredicateObligation<'tcx>>> {
+        let tcx = self.tcx();
+        let mut nested = vec![];
+
+        let upcast_principal = normalize_with_depth_to(
+            self,
+            obligation.param_env,
+            obligation.cause.clone(),
+            obligation.recursion_depth + 1,
+            unnormalized_upcast_principal,
+            &mut nested,
+        );
+
+        for bound in b_data {
+            match bound.skip_binder() {
+                // Check that a_ty's supertrait (upcast_principal) is compatible
+                // with the target (b_ty).
+                ty::ExistentialPredicate::Trait(target_principal) => {
+                    nested.extend(
+                        self.infcx
+                            .at(&obligation.cause, obligation.param_env)
+                            .sup(
+                                DefineOpaqueTypes::No,
+                                upcast_principal.map_bound(|trait_ref| {
+                                    ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
+                                }),
+                                bound.rebind(target_principal),
+                            )
+                            .map_err(|_| SelectionError::Unimplemented)?
+                            .into_obligations(),
+                    );
+                }
+                // Check that b_ty's projection is satisfied by exactly one of
+                // a_ty's projections. First, we look through the list to see if
+                // any match. If not, error. Then, if *more* than one matches, we
+                // return ambiguity. Otherwise, if exactly one matches, equate
+                // it with b_ty's projection.
+                ty::ExistentialPredicate::Projection(target_projection) => {
+                    let target_projection = bound.rebind(target_projection);
+                    let mut matching_projections =
+                        a_data.projection_bounds().filter(|source_projection| {
+                            // Eager normalization means that we can just use can_eq
+                            // here instead of equating and processing obligations.
+                            source_projection.item_def_id() == target_projection.item_def_id()
+                                && self.infcx.can_eq(
+                                    obligation.param_env,
+                                    *source_projection,
+                                    target_projection,
+                                )
+                        });
+                    let Some(source_projection) = matching_projections.next() else {
+                        return Err(SelectionError::Unimplemented);
+                    };
+                    if matching_projections.next().is_some() {
+                        return Ok(None);
+                    }
+                    nested.extend(
+                        self.infcx
+                            .at(&obligation.cause, obligation.param_env)
+                            .sup(DefineOpaqueTypes::No, source_projection, target_projection)
+                            .map_err(|_| SelectionError::Unimplemented)?
+                            .into_obligations(),
+                    );
+                }
+                // Check that b_ty's auto traits are present in a_ty's bounds.
+                ty::ExistentialPredicate::AutoTrait(def_id) => {
+                    if !a_data.auto_traits().any(|source_def_id| source_def_id == def_id) {
+                        return Err(SelectionError::Unimplemented);
+                    }
+                }
+            }
+        }
+
+        nested.push(Obligation::with_depth(
+            tcx,
+            obligation.cause.clone(),
+            obligation.recursion_depth + 1,
+            obligation.param_env,
+            ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
+        ));
+
+        Ok(Some(nested))
+    }
+
     /// Normalize `where_clause_trait_ref` and try to match it against
     /// `obligation`. If successful, return any predicates that
     /// result from the normalization.
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 1a6a253f360..b0f8ea7a05d 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -216,6 +216,11 @@ bitflags! {
         /// Does this have `ConstKind::Placeholder`?
         const HAS_CT_PLACEHOLDER          = 1 << 8;
 
+        /// Does this have placeholders?
+        const HAS_PLACEHOLDER           = TypeFlags::HAS_TY_PLACEHOLDER.bits
+                                          | TypeFlags::HAS_RE_PLACEHOLDER.bits
+                                          | TypeFlags::HAS_CT_PLACEHOLDER.bits;
+
         /// `true` if there are "names" of regions and so forth
         /// that are local to a particular fn/inferctxt
         const HAS_FREE_LOCAL_REGIONS      = 1 << 9;
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index bec0b11acd0..da60166b84d 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -2004,7 +2004,8 @@ impl Config {
                 .unwrap();
         if !(source_version == rustc_version
             || (source_version.major == rustc_version.major
-                && source_version.minor == rustc_version.minor + 1))
+                && (source_version.minor == rustc_version.minor
+                    || source_version.minor == rustc_version.minor + 1)))
         {
             let prev_version = format!("{}.{}.x", source_version.major, source_version.minor - 1);
             eprintln!(
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 6f791aec3f2..12d620b5b18 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -136,19 +136,13 @@ pub(crate) fn new_handler(
         ErrorOutputType::HumanReadable(kind) => {
             let (short, color_config) = kind.unzip();
             Box::new(
-                EmitterWriter::stderr(
-                    color_config,
-                    source_map.map(|sm| sm as _),
-                    None,
-                    fallback_bundle,
-                    short,
-                    unstable_opts.teach,
-                    diagnostic_width,
-                    false,
-                    unstable_opts.track_diagnostics,
-                    TerminalUrl::No,
-                )
-                .ui_testing(unstable_opts.ui_testing),
+                EmitterWriter::stderr(color_config, fallback_bundle)
+                    .sm(source_map.map(|sm| sm as _))
+                    .short_message(short)
+                    .teach(unstable_opts.teach)
+                    .diagnostic_width(diagnostic_width)
+                    .track_diagnostics(unstable_opts.track_diagnostics)
+                    .ui_testing(unstable_opts.ui_testing),
             )
         }
         ErrorOutputType::Json { pretty, json_rendered } => {
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index a48273a5c73..3315ccad4d3 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1,7 +1,7 @@
 use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError, TerminalUrl};
+use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::{self as hir, intravisit, CRATE_HIR_ID};
 use rustc_interface::interface;
@@ -558,33 +558,11 @@ pub(crate) fn make_test(
                 rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
                 false,
             );
-            supports_color = EmitterWriter::stderr(
-                ColorConfig::Auto,
-                None,
-                None,
-                fallback_bundle.clone(),
-                false,
-                false,
-                Some(80),
-                false,
-                false,
-                TerminalUrl::No,
-            )
-            .supports_color();
+            supports_color = EmitterWriter::stderr(ColorConfig::Auto, fallback_bundle.clone())
+                .diagnostic_width(Some(80))
+                .supports_color();
 
-            let emitter = EmitterWriter::new(
-                Box::new(io::sink()),
-                None,
-                None,
-                fallback_bundle,
-                false,
-                false,
-                false,
-                None,
-                false,
-                false,
-                TerminalUrl::No,
-            );
+            let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle);
 
             // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
             let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
@@ -760,19 +738,7 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
                 false,
             );
 
-            let emitter = EmitterWriter::new(
-                Box::new(io::sink()),
-                None,
-                None,
-                fallback_bundle,
-                false,
-                false,
-                false,
-                None,
-                false,
-                false,
-                TerminalUrl::No,
-            );
+            let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle);
 
             let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
             let sess = ParseSess::with_span_handler(handler, sm);
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index b653f61d536..2b302988734 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -68,7 +68,7 @@
 	--test-arrow-color: #dedede;
 	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
 	--test-arrow-hover-color: #dedede;
-	--test-arrow-hover-background-color: #4e8bca;
+	--test-arrow-hover-background-color: rgb(78, 139, 202);
 	--target-background-color: #494a3d;
 	--target-border-color: #bb7410;
 	--kbd-color: #000;
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 6be25fc0544..56fd8cbef12 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -68,7 +68,7 @@
 	--test-arrow-color: #f5f5f5;
 	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
 	--test-arrow-hover-color: #f5f5f5;
-	--test-arrow-hover-background-color: #4e8bca;
+	--test-arrow-hover-background-color: rgb(78, 139, 202);
 	--target-background-color: #fdffd3;
 	--target-border-color: #ad7c37;
 	--kbd-color: #000;
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index a5ec979ccd9..137bd9c9451 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -800,7 +800,7 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo
         && parent.span.ctxt() == e.span.ctxt()
     {
         match parent.kind {
-            ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _)
+            ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _)
                 if child.hir_id == e.hir_id => true,
             ExprKind::Field(_, _) | ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) => true,
             _ => false,
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index 00f70e586f4..2c4d93e33ba 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -16,7 +16,7 @@ use rustc_ast::token::CommentKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::{Applicability, Handler, SuggestionStyle, TerminalUrl};
+use rustc_errors::{Applicability, Handler, SuggestionStyle};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{AnonConst, Expr};
@@ -718,16 +718,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
                     rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
                 let emitter = EmitterWriter::new(
                     Box::new(io::sink()),
-                    None,
-                    None,
                     fallback_bundle,
-                    false,
-                    false,
-                    false,
-                    None,
-                    false,
-                    false,
-                    TerminalUrl::No,
                 );
                 let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
                 let sess = ParseSess::with_span_handler(handler, sm);
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 83445c7a0ca..57df5683c9d 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -221,7 +221,7 @@ fn is_mutated_static(e: &hir::Expr<'_>) -> bool {
     match e.kind {
         Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)),
         Path(_) => true,
-        Field(inner, _) | Index(inner, _) => is_mutated_static(inner),
+        Field(inner, _) | Index(inner, _, _) => is_mutated_static(inner),
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index 01a7c497cbe..f507f45d5bb 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -254,7 +254,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
                 // Checking for slice indexing
                 let parent_id = map.parent_id(expr.hir_id);
                 if let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id);
-                if let hir::ExprKind::Index(_, index_expr) = parent_expr.kind;
+                if let hir::ExprKind::Index(_, index_expr, _) = parent_expr.kind;
                 if let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr);
                 if let Ok(index_value) = index_value.try_into();
                 if index_value < max_suggested_slice;
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index 22c14d9b04d..4f4f571773f 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
             return;
         }
 
-        if let ExprKind::Index(array, index) = &expr.kind {
+        if let ExprKind::Index(array, index, _) = &expr.kind {
             let note = "the suggestion might not be applicable in constant blocks";
             let ty = cx.typeck_results().expr_ty(array).peel_refs();
             if let Some(range) = higher::Range::hir(index) {
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index 7d1f8ef29c8..d3fd0e8639e 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -60,8 +60,8 @@ pub(super) fn check<'tcx>(
                     o.and_then(|(lhs, rhs)| {
                         let rhs = fetch_cloned_expr(rhs);
                         if_chain! {
-                            if let ExprKind::Index(base_left, idx_left) = lhs.kind;
-                            if let ExprKind::Index(base_right, idx_right) = rhs.kind;
+                            if let ExprKind::Index(base_left, idx_left, _) = lhs.kind;
+                            if let ExprKind::Index(base_right, idx_right, _) = rhs.kind;
                             if let Some(ty) = get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_left));
                             if get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_right)).is_some();
                             if let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts);
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 2c20e9e8693..c4af46b8fd3 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -319,7 +319,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
 
         if_chain! {
             // an index op
-            if let ExprKind::Index(seqexpr, idx) = expr.kind;
+            if let ExprKind::Index(seqexpr, idx, _) = expr.kind;
             if !self.check(idx, seqexpr, expr);
             then {
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 7da9121fbb3..dd77c69ef88 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -162,7 +162,7 @@ fn never_loop_expr<'tcx>(
         ExprKind::Binary(_, e1, e2)
         | ExprKind::Assign(e1, e2, _)
         | ExprKind::AssignOp(_, e1, e2)
-        | ExprKind::Index(e1, e2) => never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id),
+        | ExprKind::Index(e1, e2, _) => never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id),
         ExprKind::Loop(b, _, _, _) => {
             // Break can come from the inner loop so remove them.
             absorb_break(never_loop_block(cx, b, ignore_ids, main_loop_id))
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index 8019f906aca..5153070cfe6 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -113,7 +113,7 @@ fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExp
 
             // Shouldn't have side effects, but there's no way to trace which field is used. So forget which fields have
             // already been seen.
-            ExprKind::Index(base, idx) if !idx.can_have_side_effects() => {
+            ExprKind::Index(base, idx, _) if !idx.can_have_side_effects() => {
                 can_move = false;
                 fields.clear();
                 e = base;
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 2b9def1a688..201bb56efcd 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -204,7 +204,7 @@ fn find_stripping<'tcx>(
             if_chain! {
                 if is_ref_str(self.cx, ex);
                 let unref = peel_ref(ex);
-                if let ExprKind::Index(indexed, index) = &unref.kind;
+                if let ExprKind::Index(indexed, index, _) = &unref.kind;
                 if let Some(higher::Range { start, end, .. }) = higher::Range::hir(index);
                 if let ExprKind::Path(path) = &indexed.kind;
                 if self.cx.qpath_res(path, ex.hir_id) == self.target;
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs b/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs
index 89dcac4d849..bd53ebd48c8 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs
@@ -12,7 +12,7 @@ use super::MATCH_ON_VEC_ITEMS;
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) {
     if_chain! {
         if let Some(idx_expr) = is_vec_indexing(cx, scrutinee);
-        if let ExprKind::Index(vec, idx) = idx_expr.kind;
+        if let ExprKind::Index(vec, idx, _) = idx_expr.kind;
 
         then {
             // FIXME: could be improved to suggest surrounding every pattern with Some(_),
@@ -36,7 +36,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) {
 
 fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     if_chain! {
-        if let ExprKind::Index(array, index) = expr.kind;
+        if let ExprKind::Index(array, index, _) = expr.kind;
         if is_vector(cx, array);
         if !is_full_range(cx, index);
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
index ce7f9997b5a..ac7bc9bcca4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
@@ -12,7 +12,7 @@ use super::FILTER_NEXT;
 fn path_to_local(expr: &hir::Expr<'_>) -> Option<hir::HirId> {
     match expr.kind {
         hir::ExprKind::Field(f, _) => path_to_local(f),
-        hir::ExprKind::Index(recv, _) => path_to_local(recv),
+        hir::ExprKind::Index(recv, _, _) => path_to_local(recv),
         hir::ExprKind::Path(hir::QPath::Resolved(
             _,
             hir::Path {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
index e2029da8081..8f885e9f729 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
@@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
     if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() {
         // caller is a Slice
         if_chain! {
-            if let hir::ExprKind::Index(caller_var, index_expr) = &caller_expr.kind;
+            if let hir::ExprKind::Index(caller_var, index_expr, _) = &caller_expr.kind;
             if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
                 = higher::Range::hir(index_expr);
             if let hir::ExprKind::Lit(start_lit) = &start_expr.kind;
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index 57ec3a1f1e6..367cd6bd413 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -239,7 +239,7 @@ fn check_expr<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, expr: &'tcx Expr<'_>) -> St
         | ExprKind::MethodCall(..)
         | ExprKind::Call(_, _)
         | ExprKind::Assign(..)
-        | ExprKind::Index(_, _)
+        | ExprKind::Index(..)
         | ExprKind::Repeat(_, _)
         | ExprKind::Struct(_, _, _) => {
             walk_expr(vis, expr);
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index 46457400abc..f6b87b071b9 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -119,7 +119,7 @@ fn condition_needs_parentheses(e: &Expr<'_>) -> bool {
     | ExprKind::Call(i, _)
     | ExprKind::Cast(i, _)
     | ExprKind::Type(i, _)
-    | ExprKind::Index(i, _) = inner.kind
+    | ExprKind::Index(i, _, _) = inner.kind
     {
         if matches!(
             i.kind,
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index e6d3e72d1e6..5f2a324b05f 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 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match peel_blocks(expr).kind {
         ExprKind::Lit(..) | ExprKind::Closure { .. } => true,
         ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)),
-        ExprKind::Index(a, b) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b),
+        ExprKind::Index(a, b, _) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b),
         ExprKind::Array(v) | ExprKind::Tup(v) => v.iter().all(|val| has_no_effect(cx, val)),
         ExprKind::Repeat(inner, _)
         | ExprKind::Cast(inner, _)
@@ -263,7 +263,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
         return None;
     }
     match expr.kind {
-        ExprKind::Index(a, b) => Some(vec![a, b]),
+        ExprKind::Index(a, b, _) => Some(vec![a, b]),
         ExprKind::Binary(ref binop, a, b) if binop.node != BinOpKind::And && binop.node != BinOpKind::Or => {
             Some(vec![a, b])
         },
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index a70692d8ff8..243192385c2 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -438,7 +438,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
 
                             dereferenced_expr = parent_expr;
                         },
-                        ExprKind::Index(e, _) if ptr::eq(&**e, cur_expr) => {
+                        ExprKind::Index(e, _, _) if ptr::eq(&**e, cur_expr) => {
                             // `e[i]` => desugared to `*Index::index(&e, i)`,
                             // meaning `e` must be referenced.
                             // no need to go further up since a method call is involved now.
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 42299d8d42f..8009b00b4b9 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -695,7 +695,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
                         }
                     },
                     // Indexing is fine for currently supported types.
-                    ExprKind::Index(e, _) if e.hir_id == child_id => (),
+                    ExprKind::Index(e, _, _) if e.hir_id == child_id => (),
                     _ => set_skip_flag(),
                 },
                 _ => set_skip_flag(),
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 8277ce724d4..4abfa0fc35c 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
         if_chain! {
             if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind;
             if addressee.span.ctxt() == ctxt;
-            if let ExprKind::Index(indexed, range) = addressee.kind;
+            if let ExprKind::Index(indexed, range, _) = addressee.kind;
             if is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull);
             then {
                 let (expr_ty, expr_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(expr));
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 4d45091f4b5..76f463fff7d 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -190,7 +190,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd {
                     );
                 }
             },
-            ExprKind::Index(target, _idx) => {
+            ExprKind::Index(target, _idx, _) => {
                 let e_ty = cx.typeck_results().expr_ty(target).peel_refs();
                 if e_ty.is_str() || is_type_lang_item(cx, e_ty, LangItem::String) {
                     span_lint(
@@ -262,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
 
             // Find string::as_bytes
             if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args[0].kind;
-            if let ExprKind::Index(left, right) = args.kind;
+            if let ExprKind::Index(left, right, _) = args.kind;
             let (method_names, expressions, _) = method_calls(left, 1);
             if method_names.len() == 1;
             if expressions.len() == 1;
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index e2cdc48b583..23d6e2a845f 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -572,7 +572,7 @@ fn ident_difference_expr_with_base_location(
         | (AddrOf(_, _, _), AddrOf(_, _, _))
         | (Path(_, _), Path(_, _))
         | (Range(_, _, _), Range(_, _, _))
-        | (Index(_, _), Index(_, _))
+        | (Index(_, _, _), Index(_, _, _))
         | (Field(_, _), Field(_, _))
         | (AssignOp(_, _, _), AssignOp(_, _, _))
         | (Assign(_, _, _), Assign(_, _, _))
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 98158ed0aee..548fabb8b73 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -86,8 +86,8 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
     let mut applicability = Applicability::MachineApplicable;
 
     if !can_mut_borrow_both(cx, e1, e2) {
-        if let ExprKind::Index(lhs1, idx1) = e1.kind
-            && let ExprKind::Index(lhs2, idx2) = e2.kind
+        if let ExprKind::Index(lhs1, idx1, _) = e1.kind
+            && let ExprKind::Index(lhs2, idx2, _) = e2.kind
             && eq_expr_value(cx, lhs1, lhs2)
             && e1.span.ctxt() == ctxt
             && e2.span.ctxt() == ctxt
diff --git a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
index 3766b8f8ed1..b6b653f6610 100644
--- a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
+++ b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
@@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryAssignment {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Assign(target, ..) = &expr.kind {
             let mut base = target;
-            while let ExprKind::Field(f, _) | ExprKind::Index(f, _) = &base.kind {
+            while let ExprKind::Field(f, _) | ExprKind::Index(f, _, _) = &base.kind {
                 base = f;
             }
             if is_temporary(base) && !is_adjusted(cx, base) {
diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
index 7eec6982092..78ad52d8a87 100644
--- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
@@ -103,11 +103,11 @@ fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &
         // Fix #11100
         && tys.iter().all_equal()
         && let Some(locals) = (match first.kind {
-            ExprKind::Index(_, _) => elements
+            ExprKind::Index(..) => elements
                 .iter()
                 .enumerate()
                 .map(|(i, i_expr)| -> Option<&'tcx Expr<'tcx>> {
-                    if let ExprKind::Index(lhs, index) = i_expr.kind
+                    if let ExprKind::Index(lhs, index, _) = i_expr.kind
                         && let ExprKind::Lit(lit) = index.kind
                         && let LitKind::Int(val, _) = lit.node
                     {
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 6b51974d739..f02c33cc674 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -526,7 +526,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 self.ident(field_name);
                 self.expr(object);
             },
-            ExprKind::Index(object, index) => {
+            ExprKind::Index(object, index, _) => {
                 bind!(self, object, index);
                 kind!("Index({object}, {index})");
                 self.expr(object);
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index 1d4fc24eb6c..3fa51216c77 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -88,7 +88,7 @@ impl VecPushSearcher {
                     let mut last_place = parent;
                     while let Some(parent) = get_parent_expr(cx, last_place) {
                         if matches!(parent.kind, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Field(..))
-                            || matches!(parent.kind, ExprKind::Index(e, _) if e.hir_id == last_place.hir_id)
+                            || matches!(parent.kind, ExprKind::Index(e, _, _) if e.hir_id == last_place.hir_id)
                         {
                             last_place = parent;
                         } else {
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 7e42924603a..2d0d6f559ad 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -178,7 +178,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r),
         (Break(ll, le), Break(rl, re)) => eq_label(ll, rl) && eq_expr_opt(le, re),
         (Continue(ll), Continue(rl)) => eq_label(ll, rl),
-        (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2), Index(r1, r2)) => eq_expr(l1, r1) && eq_expr(l2, r2),
+        (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => eq_expr(l1, r1) && eq_expr(l2, r2),
         (AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv),
         (Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp),
         (Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, eq_arm),
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 89f8a65c5ae..60fab1ec41a 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -163,7 +163,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
         ) => (Pat::Str("unsafe"), Pat::Str("}")),
         ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")),
         ExprKind::Field(e, name) => (expr_search_pat(tcx, e).0, Pat::Sym(name.name)),
-        ExprKind::Index(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")),
+        ExprKind::Index(e, _, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")),
         ExprKind::Path(ref path) => qpath_search_pat(path),
         ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat(tcx, e).1),
         ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")),
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index f19e09a18ec..d38e3f1ae76 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -394,7 +394,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                     }
                 }
             },
-            ExprKind::Index(arr, index) => self.index(arr, index),
+            ExprKind::Index(arr, index, _) => self.index(arr, index),
             ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
             ExprKind::Field(local_expr, ref field) => {
                 let result = self.expr(local_expr);
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 3c969572b8e..0bcefba75a7 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -185,7 +185,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                         .type_dependent_def_id(e.hir_id)
                         .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, true));
                 },
-                ExprKind::Index(_, e) => {
+                ExprKind::Index(_, e, _) => {
                     let ty = self.cx.typeck_results().expr_ty_adjusted(e);
                     if is_copy(self.cx, ty) && !ty.is_ref() {
                         self.eagerness |= NoChange;
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 85b3b005f93..fdc35cd4ddf 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -299,7 +299,7 @@ impl HirEqInterExpr<'_, '_, '_> {
             (&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => {
                 l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp)
             },
-            (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
+            (&ExprKind::Index(la, li, _), &ExprKind::Index(ra, ri, _)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
             (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
                 self.eq_expr(lc, rc) && self.eq_expr(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r))
             },
@@ -730,7 +730,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 self.hash_expr(e);
                 self.hash_name(f.name);
             },
-            ExprKind::Index(a, i) => {
+            ExprKind::Index(a, i, _) => {
                 self.hash_expr(a);
                 self.hash_expr(i);
             },
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index cf30930b76e..4cd8a8c3325 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -735,7 +735,7 @@ fn projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &'
     let mut result = vec![];
     let root = loop {
         match e.kind {
-            ExprKind::Index(ep, _) | ExprKind::Field(ep, _) => {
+            ExprKind::Index(ep, _, _) | ExprKind::Field(ep, _) => {
                 result.push(e);
                 e = ep;
             },
@@ -782,7 +782,7 @@ pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -
                     return true;
                 }
             },
-            (ExprKind::Index(_, i1), ExprKind::Index(_, i2)) => {
+            (ExprKind::Index(_, i1, _), ExprKind::Index(_, i2, _)) => {
                 if !eq_expr_value(cx, i1, i2) {
                     return false;
                 }
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 5d7e1494fcf..a43a81bc63a 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -1011,6 +1011,8 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
                         },
                         // note: unable to trigger `Subslice` kind in tests
                         ProjectionKind::Subslice => (),
+                        // Doesn't have surface syntax. Only occurs in patterns.
+                        ProjectionKind::OpaqueCast => (),
                         ProjectionKind::Deref => {
                             // Explicit derefs are typically handled later on, but
                             // some items do not need explicit deref, such as array accesses,
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index 45b5483e323..0669ea72eb3 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -31,7 +31,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
     let certainty = match &expr.kind {
         ExprKind::Unary(_, expr)
         | ExprKind::Field(expr, _)
-        | ExprKind::Index(expr, _)
+        | ExprKind::Index(expr, _, _)
         | ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr),
 
         ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr))),
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 09f447b27eb..f83988a6e32 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -329,7 +329,7 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) ->
                         && self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {},
                 ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).is_ref() => (),
                 ExprKind::Unary(_, e) if self.cx.typeck_results().expr_ty(e).peel_refs().is_primitive_ty() => (),
-                ExprKind::Index(base, _)
+                ExprKind::Index(base, _, _)
                     if matches!(
                         self.cx.typeck_results().expr_ty(base).peel_refs().kind(),
                         ty::Slice(_) | ty::Array(..)
@@ -629,7 +629,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
                     helper(typeck, true, arg, f)?;
                 }
             },
-            ExprKind::Index(borrowed, consumed)
+            ExprKind::Index(borrowed, consumed, _)
             | ExprKind::Assign(borrowed, consumed, _)
             | ExprKind::AssignOp(_, borrowed, consumed) => {
                 helper(typeck, false, borrowed, f)?;
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 07a54cb26d3..c1987420417 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2466,8 +2466,13 @@ impl<'test> TestCx<'test> {
             rustc.args(&["-A", "unused"]);
         }
 
-        // Allow tests to use internal features.
-        rustc.args(&["-A", "internal_features"]);
+        // #[cfg(not(bootstrap)] unconditionally pass flag after beta bump
+        // since `ui-fulldeps --stage=1` builds using the stage 0 compiler,
+        // which doesn't have this lint.
+        if !(self.config.stage_id.starts_with("stage1-") && self.config.suite == "ui-fulldeps") {
+            // Allow tests to use internal features.
+            rustc.args(&["-A", "internal_features"]);
+        }
 
         if self.props.force_host {
             self.maybe_add_external_args(&mut rustc, &self.config.host_rustcflags);
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index e929091b396..75e4b5f8466 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::mir::{Mutability, RetagKind};
 use rustc_middle::ty::{
     self,
-    layout::{HasParamEnv, LayoutOf},
+    layout::HasParamEnv,
     Ty,
 };
 use rustc_target::abi::{Abi, Align, Size};
@@ -993,8 +993,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         // We have to turn the place into a pointer to use the usual retagging logic.
         // (The pointer type does not matter, so we use a raw pointer.)
-        let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, place.layout.ty))?;
-        let ptr = ImmTy::from_immediate(place.to_ref(this), ptr_layout);
+        let ptr = this.mplace_to_ref(place)?;
         // Reborrow it. With protection! That is the entire point.
         let new_perm = NewPermission::Uniform {
             perm: Permission::Unique,
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index 51006ee97c9..c584eae220e 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -7,7 +7,7 @@ use rustc_middle::{
     mir::{Mutability, RetagKind},
     ty::{
         self,
-        layout::{HasParamEnv, LayoutOf},
+        layout::HasParamEnv,
         Ty,
     },
 };
@@ -493,8 +493,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         // We have to turn the place into a pointer to use the usual retagging logic.
         // (The pointer type does not matter, so we use a raw pointer.)
-        let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, place.layout.ty))?;
-        let ptr = ImmTy::from_immediate(place.to_ref(this), ptr_layout);
+        let ptr = this.mplace_to_ref(place)?;
         // Reborrow it. With protection! That is the entire point.
         let new_perm = NewPermission {
             initial_state: Permission::new_active(),
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index 739afb4e0ac..c3c07f310bf 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -256,7 +256,7 @@ pub(crate) fn format_expr(
             shape,
             SeparatorPlace::Back,
         ),
-        ast::ExprKind::Index(ref expr, ref index) => {
+        ast::ExprKind::Index(ref expr, ref index, _) => {
             rewrite_index(&**expr, &**index, context, shape)
         }
         ast::ExprKind::Repeat(ref expr, ref repeats) => rewrite_pair(
@@ -1342,7 +1342,7 @@ pub(crate) fn is_simple_expr(expr: &ast::Expr) -> bool {
         | ast::ExprKind::Field(ref expr, _)
         | ast::ExprKind::Try(ref expr)
         | ast::ExprKind::Unary(_, ref expr) => is_simple_expr(expr),
-        ast::ExprKind::Index(ref lhs, ref rhs) => is_simple_expr(lhs) && is_simple_expr(rhs),
+        ast::ExprKind::Index(ref lhs, ref rhs, _) => is_simple_expr(lhs) && is_simple_expr(rhs),
         ast::ExprKind::Repeat(ref lhs, ref rhs) => {
             is_simple_expr(lhs) && is_simple_expr(&*rhs.value)
         }
diff --git a/src/tools/rustfmt/src/matches.rs b/src/tools/rustfmt/src/matches.rs
index aac5e59b860..4c37116f120 100644
--- a/src/tools/rustfmt/src/matches.rs
+++ b/src/tools/rustfmt/src/matches.rs
@@ -594,7 +594,7 @@ fn can_flatten_block_around_this(body: &ast::Expr) -> bool {
         ast::ExprKind::AddrOf(_, _, ref expr)
         | ast::ExprKind::Try(ref expr)
         | ast::ExprKind::Unary(_, ref expr)
-        | ast::ExprKind::Index(ref expr, _)
+        | ast::ExprKind::Index(ref expr, _, _)
         | ast::ExprKind::Cast(ref expr, _) => can_flatten_block_around_this(expr),
         _ => false,
     }
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index aa75b477473..945e3e42fdd 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
 use rustc_data_structures::sync::{Lrc, Send};
 use rustc_errors::emitter::{Emitter, EmitterWriter};
 use rustc_errors::translation::Translate;
-use rustc_errors::{ColorConfig, Diagnostic, Handler, Level as DiagnosticLevel, TerminalUrl};
+use rustc_errors::{ColorConfig, Diagnostic, Handler, Level as DiagnosticLevel};
 use rustc_session::parse::ParseSess as RawParseSess;
 use rustc_span::{
     source_map::{FilePathMapping, SourceMap},
@@ -139,18 +139,7 @@ fn default_handler(
             rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
             false,
         );
-        Box::new(EmitterWriter::stderr(
-            emit_color,
-            Some(source_map.clone()),
-            None,
-            fallback_bundle,
-            false,
-            false,
-            None,
-            false,
-            false,
-            TerminalUrl::No,
-        ))
+        Box::new(EmitterWriter::stderr(emit_color, fallback_bundle).sm(Some(source_map.clone())))
     };
     Handler::with_emitter(Box::new(SilentOnIgnoredFilesEmitter {
         has_non_ignorable_parser_errors: false,
diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs
index 890a05b8c82..4fc5a9b6896 100644
--- a/src/tools/rustfmt/src/utils.rs
+++ b/src/tools/rustfmt/src/utils.rs
@@ -441,7 +441,7 @@ pub(crate) fn left_most_sub_expr(e: &ast::Expr) -> &ast::Expr {
         | ast::ExprKind::Assign(ref e, _, _)
         | ast::ExprKind::AssignOp(_, ref e, _)
         | ast::ExprKind::Field(ref e, _)
-        | ast::ExprKind::Index(ref e, _)
+        | ast::ExprKind::Index(ref e, _, _)
         | ast::ExprKind::Range(Some(ref e), _, _)
         | ast::ExprKind::Try(ref e) => left_most_sub_expr(e),
         _ => e,
@@ -479,7 +479,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
         | ast::ExprKind::Match(..) => repr.contains('\n'),
         ast::ExprKind::Paren(ref expr)
         | ast::ExprKind::Binary(_, _, ref expr)
-        | ast::ExprKind::Index(_, ref expr)
+        | ast::ExprKind::Index(_, ref expr, _)
         | ast::ExprKind::Unary(_, ref expr)
         | ast::ExprKind::Try(ref expr)
         | ast::ExprKind::Yield(Some(ref expr)) => is_block_expr(context, expr, repr),
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index a015c36d7eb..22e9b46347a 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -138,8 +138,12 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "crossbeam-utils",
     "crypto-common",
     "cstr",
+    "darling",
+    "darling_core",
+    "darling_macro",
     "datafrog",
     "derive_more",
+    "derive_setters",
     "digest",
     "displaydoc",
     "dissimilar",
@@ -158,6 +162,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "fluent-bundle",
     "fluent-langneg",
     "fluent-syntax",
+    "fnv",
     "fortanix-sgx-abi",
     "generic-array",
     "getopts",
@@ -171,6 +176,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "icu_provider",
     "icu_provider_adapters",
     "icu_provider_macros",
+    "ident_case",
     "indexmap",
     "instant",
     "intl-memoizer",
@@ -245,6 +251,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "stable_deref_trait",
     "stacker",
     "static_assertions",
+    "strsim",
     "syn",
     "synstructure",
     "tempfile",
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 44c7c07d3a0..930b7408390 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
 const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
 const ISSUES_ENTRY_LIMIT: usize = 1893;
-const ROOT_ENTRY_LIMIT: usize = 873;
+const ROOT_ENTRY_LIMIT: usize = 866;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/rustdoc-gui/run-on-hover.goml b/tests/rustdoc-gui/run-on-hover.goml
index b5fc49eacac..1f87febcec6 100644
--- a/tests/rustdoc-gui/run-on-hover.goml
+++ b/tests/rustdoc-gui/run-on-hover.goml
@@ -33,22 +33,22 @@ define-function: (
 
 call-function: ("check-run-button", {
     "theme": "ayu",
-    "color": "rgb(120, 135, 151)",
+    "color": "#788797",
     "background": "rgba(57, 175, 215, 0.09)",
-    "hover_color": "rgb(197, 197, 197)",
+    "hover_color": "#c5c5c5",
     "hover_background": "rgba(57, 175, 215, 0.37)",
 })
 call-function: ("check-run-button", {
     "theme": "dark",
-    "color": "rgb(222, 222, 222)",
+    "color": "#dedede",
     "background": "rgba(78, 139, 202, 0.2)",
-    "hover_color": "rgb(222, 222, 222)",
+    "hover_color": "#dedede",
     "hover_background": "rgb(78, 139, 202)",
 })
 call-function: ("check-run-button", {
     "theme": "light",
-    "color": "rgb(245, 245, 245)",
+    "color": "#f5f5f5",
     "background": "rgba(78, 139, 202, 0.2)",
-    "hover_color": "rgb(245, 245, 245)",
+    "hover_color": "#f5f5f5",
     "hover_background": "rgb(78, 139, 202)",
 })
diff --git a/tests/rustdoc-json/type/inherent_associated_type_bound.rs b/tests/rustdoc-json/type/inherent_associated_type_bound.rs
index 2e9b13d0cac..8e39f471824 100644
--- a/tests/rustdoc-json/type/inherent_associated_type_bound.rs
+++ b/tests/rustdoc-json/type/inherent_associated_type_bound.rs
@@ -5,14 +5,15 @@
 // @set Carrier = '$.index[*][?(@.name=="Carrier")].id'
 pub struct Carrier<'a>(&'a ());
 
-// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.generic_params[*].name' \""'b"\"
-// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier
-// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].lifetime' \""'b"\"
-// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.name' '"Focus"'
-// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.trait' null
-// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"'
-
-pub type User = for<'b> fn(Carrier<'b>::Focus<i32>);
+// @count "$.index[*][?(@.name=='user')].inner.function.decl.inputs[*]" 1
+// @is "$.index[*][?(@.name=='user')].inner.function.decl.inputs[0][0]" '"_"'
+// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.generic_params[*].name' \""'b"\"
+// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier
+// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].lifetime' \""'b"\"
+// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.name' '"Focus"'
+// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.trait' null
+// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"'
+pub fn user(_: for<'b> fn(Carrier<'b>::Focus<i32>)) {}
 
 impl<'a> Carrier<'a> {
     pub type Focus<T> = &'a mut T;
diff --git a/tests/rustdoc-json/type/inherent_associated_type_projections.rs b/tests/rustdoc-json/type/inherent_associated_type_projections.rs
index 942e323efca..d12e5f4a784 100644
--- a/tests/rustdoc-json/type/inherent_associated_type_projections.rs
+++ b/tests/rustdoc-json/type/inherent_associated_type_projections.rs
@@ -5,11 +5,13 @@
 // @set Parametrized = '$.index[*][?(@.name=="Parametrized")].id'
 pub struct Parametrized<T>(T);
 
-// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.self_type.resolved_path.id' $Parametrized
-// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].type.primitive' \"i32\"
-// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.name' '"Proj"'
-// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.trait' null
-pub type Test = Parametrized<i32>::Proj;
+// @count "$.index[*][?(@.name=='test')].inner.function.decl.inputs[*]" 1
+// @is "$.index[*][?(@.name=='test')].inner.function.decl.inputs[0][0]" '"_"'
+// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Parametrized
+// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].type.primitive' \"i32\"
+// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.name' '"Proj"'
+// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.trait' null
+pub fn test(_: Parametrized<i32>::Proj) {}
 
 /// param_bool
 impl Parametrized<bool> {
diff --git a/tests/rustdoc/inherent-projections.rs b/tests/rustdoc/inherent-projections.rs
index 9bda0acaf83..25f51282617 100644
--- a/tests/rustdoc/inherent-projections.rs
+++ b/tests/rustdoc/inherent-projections.rs
@@ -13,8 +13,8 @@ impl Owner {
 }
 
 // Make sure we handle bound vars correctly.
-// @has 'inherent_projections/type.User.html' '//pre[@class="rust item-decl"]' "for<'a> fn(_: Carrier<'a>::Focus)"
-pub type User = for<'a> fn(Carrier<'a>::Focus);
+// @has 'inherent_projections/fn.user.html' '//pre[@class="rust item-decl"]' "user(_: for<'a> fn(_: Carrier<'a>::Focus))"
+pub fn user(_: for<'a> fn(Carrier<'a>::Focus)) {}
 
 pub struct Carrier<'a>(&'a ());
 
@@ -27,11 +27,11 @@ impl<'a> Carrier<'a> {
 // FIXME(inherent_associated_types): Below we link to `Proj` but we should link to `Proj-1`.
 // The current test checks for the buggy behavior for demonstration purposes.
 
-// @has 'inherent_projections/type.Test.html'
-// @has - '//pre[@class="rust item-decl"]' "Parametrized<i32>"
+// @has 'inherent_projections/fn.test.html'
+// @has - '//pre[@class="rust item-decl"]' "test(_: Parametrized<i32>::Proj)"
 // @has - '//pre[@class="rust item-decl"]//a[@class="associatedtype"]/@href' 'struct.Parametrized.html#associatedtype.Proj'
 // @!has - '//pre[@class="rust item-decl"]//a[@class="associatedtype"]/@href' 'struct.Parametrized.html#associatedtype.Proj-1'
-pub type Test = Parametrized<i32>::Proj;
+pub fn test(_: Parametrized<i32>::Proj) {}
 
 pub struct Parametrized<T>(T);
 
diff --git a/tests/ui/array-slice-vec/slice-2.stderr b/tests/ui/array-slice-vec/slice-2.stderr
index 561feb90f0a..b122b46914c 100644
--- a/tests/ui/array-slice-vec/slice-2.stderr
+++ b/tests/ui/array-slice-vec/slice-2.stderr
@@ -1,26 +1,26 @@
 error[E0608]: cannot index into a value of type `Foo`
-  --> $DIR/slice-2.rs:7:6
+  --> $DIR/slice-2.rs:7:7
    |
 LL |     &x[..];
-   |      ^^^^^
+   |       ^^^^
 
 error[E0608]: cannot index into a value of type `Foo`
-  --> $DIR/slice-2.rs:8:6
+  --> $DIR/slice-2.rs:8:7
    |
 LL |     &x[Foo..];
-   |      ^^^^^^^^
+   |       ^^^^^^^
 
 error[E0608]: cannot index into a value of type `Foo`
-  --> $DIR/slice-2.rs:9:6
+  --> $DIR/slice-2.rs:9:7
    |
 LL |     &x[..Foo];
-   |      ^^^^^^^^
+   |       ^^^^^^^
 
 error[E0608]: cannot index into a value of type `Foo`
-  --> $DIR/slice-2.rs:10:6
+  --> $DIR/slice-2.rs:10:7
    |
 LL |     &x[Foo..Foo];
-   |      ^^^^^^^^^^^
+   |       ^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/associated-inherent-types/issue-111879-0.rs b/tests/ui/associated-inherent-types/issue-111879-0.rs
index e37f7d34ab5..d01354465df 100644
--- a/tests/ui/associated-inherent-types/issue-111879-0.rs
+++ b/tests/ui/associated-inherent-types/issue-111879-0.rs
@@ -5,10 +5,8 @@
 
 pub struct Carrier<'a>(&'a ());
 
-pub type User = for<'b> fn(Carrier<'b>::Focus<i32>);
-
 impl<'a> Carrier<'a> {
-    pub type Focus<T> = &'a mut User; //~ ERROR overflow evaluating associated type
+    pub type Focus<T> = &'a mut for<'b> fn(Carrier<'b>::Focus<i32>); //~ ERROR overflow evaluating associated type
 }
 
 fn main() {}
diff --git a/tests/ui/associated-inherent-types/issue-111879-0.stderr b/tests/ui/associated-inherent-types/issue-111879-0.stderr
index 7bdbad44017..f6367c88aea 100644
--- a/tests/ui/associated-inherent-types/issue-111879-0.stderr
+++ b/tests/ui/associated-inherent-types/issue-111879-0.stderr
@@ -1,8 +1,8 @@
 error: overflow evaluating associated type `Carrier<'b>::Focus<i32>`
-  --> $DIR/issue-111879-0.rs:11:25
+  --> $DIR/issue-111879-0.rs:9:25
    |
-LL |     pub type Focus<T> = &'a mut User;
-   |                         ^^^^^^^^^^^^
+LL |     pub type Focus<T> = &'a mut for<'b> fn(Carrier<'b>::Focus<i32>);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/associated-inherent-types/late-bound-regions.rs b/tests/ui/associated-inherent-types/late-bound-regions.rs
index 488a2cda649..1dbeb00d495 100644
--- a/tests/ui/associated-inherent-types/late-bound-regions.rs
+++ b/tests/ui/associated-inherent-types/late-bound-regions.rs
@@ -3,8 +3,6 @@
 
 // Test if we correctly normalize `S<'a>::P` with respect to late-bound regions.
 
-type Function = for<'a> fn(&'a i32) -> S<'a>::P;
-
 struct S<'a>(&'a ());
 
 trait Inter {
@@ -16,7 +14,7 @@ impl<'a> S<'a> {
 }
 
 fn ret_ref_local<'e>() -> &'e i32 {
-    let f: Function = |x| x;
+    let f: for<'a> fn(&'a i32) -> S<'a>::P = |x| x;
 
     let local = 0;
     f(&local) //~ ERROR cannot return value referencing local variable `local`
diff --git a/tests/ui/associated-inherent-types/late-bound-regions.stderr b/tests/ui/associated-inherent-types/late-bound-regions.stderr
index 4706fcca91d..0dd17b05cd0 100644
--- a/tests/ui/associated-inherent-types/late-bound-regions.stderr
+++ b/tests/ui/associated-inherent-types/late-bound-regions.stderr
@@ -1,5 +1,5 @@
 error[E0515]: cannot return value referencing local variable `local`
-  --> $DIR/late-bound-regions.rs:22:5
+  --> $DIR/late-bound-regions.rs:20:5
    |
 LL |     f(&local)
    |     ^^------^
diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs.alias.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs.alias.stderr
deleted file mode 100644
index 4396435a6dd..00000000000
--- a/tests/ui/associated-inherent-types/not-found-self-type-differs.alias.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0220]: associated type `Proj` not found for `Family<Option<()>>` in the current scope
-  --> $DIR/not-found-self-type-differs.rs:17:34
-   |
-LL | struct Family<T>(T);
-   | ---------------- associated item `Proj` not found for this struct
-...
-LL | type Alias = Family<Option<()>>::Proj;
-   |                                  ^^^^ associated item not found in `Family<Option<()>>`
-   |
-   = note: the associated type was found for
-           - `Family<()>`
-           - `Family<Result<T, ()>>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs.local.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs.local.stderr
deleted file mode 100644
index d527db02217..00000000000
--- a/tests/ui/associated-inherent-types/not-found-self-type-differs.local.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0220]: associated type `Proj` not found for `Family<PathBuf>` in the current scope
-  --> $DIR/not-found-self-type-differs.rs:21:40
-   |
-LL | struct Family<T>(T);
-   | ---------------- associated item `Proj` not found for this struct
-...
-LL |     let _: Family<std::path::PathBuf>::Proj = ();
-   |                                        ^^^^ associated item not found in `Family<PathBuf>`
-   |
-   = note: the associated type was found for
-           - `Family<()>`
-           - `Family<Result<T, ()>>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs.rs b/tests/ui/associated-inherent-types/not-found-self-type-differs.rs
index 93f58dcb6e6..76c5d4e7f69 100644
--- a/tests/ui/associated-inherent-types/not-found-self-type-differs.rs
+++ b/tests/ui/associated-inherent-types/not-found-self-type-differs.rs
@@ -1,5 +1,3 @@
-// revisions: local alias
-
 #![feature(inherent_associated_types)]
 #![allow(incomplete_features)]
 
@@ -13,10 +11,7 @@ impl<T> Family<Result<T, ()>> {
     type Proj = Self;
 }
 
-#[cfg(alias)]
-type Alias = Family<Option<()>>::Proj; //[alias]~ ERROR associated type `Proj` not found for `Family<Option<()>>`
-
 fn main() {
-    #[cfg(local)]
-    let _: Family<std::path::PathBuf>::Proj = (); //[local]~ ERROR associated type `Proj` not found for `Family<PathBuf>`
+    let _: Family<Option<()>>::Proj; //~ ERROR associated type `Proj` not found for `Family<Option<()>>`
+    let _: Family<std::path::PathBuf>::Proj = (); //~ ERROR associated type `Proj` not found for `Family<PathBuf>`
 }
diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs.stderr
new file mode 100644
index 00000000000..1871407c64f
--- /dev/null
+++ b/tests/ui/associated-inherent-types/not-found-self-type-differs.stderr
@@ -0,0 +1,29 @@
+error[E0220]: associated type `Proj` not found for `Family<Option<()>>` in the current scope
+  --> $DIR/not-found-self-type-differs.rs:15:32
+   |
+LL | struct Family<T>(T);
+   | ---------------- associated item `Proj` not found for this struct
+...
+LL |     let _: Family<Option<()>>::Proj;
+   |                                ^^^^ associated item not found in `Family<Option<()>>`
+   |
+   = note: the associated type was found for
+           - `Family<()>`
+           - `Family<Result<T, ()>>`
+
+error[E0220]: associated type `Proj` not found for `Family<PathBuf>` in the current scope
+  --> $DIR/not-found-self-type-differs.rs:16:40
+   |
+LL | struct Family<T>(T);
+   | ---------------- associated item `Proj` not found for this struct
+...
+LL |     let _: Family<std::path::PathBuf>::Proj = ();
+   |                                        ^^^^ associated item not found in `Family<PathBuf>`
+   |
+   = note: the associated type was found for
+           - `Family<()>`
+           - `Family<Result<T, ()>>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/associated-inherent-types/substitute-params-bad.rs b/tests/ui/associated-inherent-types/substitute-params-bad.rs
index 00eb1a14da4..a5d73c7b49f 100644
--- a/tests/ui/associated-inherent-types/substitute-params-bad.rs
+++ b/tests/ui/associated-inherent-types/substitute-params-bad.rs
@@ -17,7 +17,7 @@ impl<T, S> Subj<(T, S)> {
 }
 
 fn main() {
-    type A = S<()>::P;
+    let _: S<()>::P;
 
     let _: Subj<(i32, i32)>::Un = 0i32; //~ ERROR mismatched types
 }
diff --git a/tests/ui/associated-inherent-types/substitute-params.rs b/tests/ui/associated-inherent-types/substitute-params.rs
index e94d6833159..631340b2b4d 100644
--- a/tests/ui/associated-inherent-types/substitute-params.rs
+++ b/tests/ui/associated-inherent-types/substitute-params.rs
@@ -15,8 +15,7 @@ impl<T> S<(T,)> {
 
 fn main() {
     // Regression test for issue #104240.
-    type A = S<()>::P;
-    let _: A = ();
+    let _: S<()>::P = ();
 
     // Regression test for issue #107468.
     let _: S<(i32,)>::Un = 0i32;
diff --git a/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs b/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs
index b32b4288ac9..5c59f217be6 100644
--- a/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs
+++ b/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs
@@ -1,4 +1,5 @@
-// check-pass
+// FIXME(inherent_associated_types): This should be `check-pass`
+// known-bug: #108491
 // compile-flags: --crate-type=lib
 
 #![feature(inherent_associated_types)]
@@ -17,7 +18,6 @@
 
 pub type Alias<T: Bound> = (Source<T>::Assoc,);
 
-
 pub struct Source<T>(T);
 pub trait Bound {}
 
diff --git a/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.stderr b/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.stderr
new file mode 100644
index 00000000000..5e18543fc90
--- /dev/null
+++ b/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.stderr
@@ -0,0 +1,55 @@
+error[E0391]: cycle detected when expanding type alias `Alias`
+  --> $DIR/type-alias-bounds-are-enforced.rs:19:1
+   |
+LL | pub type Alias<T: Bound> = (Source<T>::Assoc,);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires computing the variances of `Source`...
+  --> $DIR/type-alias-bounds-are-enforced.rs:21:1
+   |
+LL | pub struct Source<T>(T);
+   | ^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires computing the variances for items in this crate...
+   = note: ...which again requires expanding type alias `Alias`, completing the cycle
+note: cycle used when collecting item types in top-level module
+  --> $DIR/type-alias-bounds-are-enforced.rs:5:1
+   |
+LL | / #![feature(inherent_associated_types)]
+LL | | #![allow(incomplete_features)]
+LL | |
+LL | | // Bounds on the self type play a major role in the resolution of inherent associated types (*).
+...  |
+LL | |     pub type Assoc = ();
+LL | | }
+   | |_^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error[E0391]: cycle detected when expanding type alias `Alias`
+  --> $DIR/type-alias-bounds-are-enforced.rs:19:1
+   |
+LL | pub type Alias<T: Bound> = (Source<T>::Assoc,);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires computing the variances of `Source`...
+  --> $DIR/type-alias-bounds-are-enforced.rs:21:1
+   |
+LL | pub struct Source<T>(T);
+   | ^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires computing the variances for items in this crate...
+   = note: ...which again requires expanding type alias `Alias`, completing the cycle
+note: cycle used when collecting item types in top-level module
+  --> $DIR/type-alias-bounds-are-enforced.rs:5:1
+   |
+LL | / #![feature(inherent_associated_types)]
+LL | | #![allow(incomplete_features)]
+LL | |
+LL | | // Bounds on the self type play a major role in the resolution of inherent associated types (*).
+...  |
+LL | |     pub type Assoc = ();
+LL | | }
+   | |_^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/async-await/track-caller/async-block.afn.stderr b/tests/ui/async-await/track-caller/async-block.afn.stderr
new file mode 100644
index 00000000000..2302722eecc
--- /dev/null
+++ b/tests/ui/async-await/track-caller/async-block.afn.stderr
@@ -0,0 +1,30 @@
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-block.rs:8:13
+   |
+LL |     let _ = #[track_caller] async {
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-block.rs:15:13
+   |
+LL |     let _ = #[track_caller] async {
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-block.rs:23:17
+   |
+LL |         let _ = #[track_caller] async {
+   |                 ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/async-await/track-caller/async-block.nofeat.stderr b/tests/ui/async-await/track-caller/async-block.nofeat.stderr
new file mode 100644
index 00000000000..2302722eecc
--- /dev/null
+++ b/tests/ui/async-await/track-caller/async-block.nofeat.stderr
@@ -0,0 +1,30 @@
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-block.rs:8:13
+   |
+LL |     let _ = #[track_caller] async {
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-block.rs:15:13
+   |
+LL |     let _ = #[track_caller] async {
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-block.rs:23:17
+   |
+LL |         let _ = #[track_caller] async {
+   |                 ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/async-await/track-caller/async-block.rs b/tests/ui/async-await/track-caller/async-block.rs
index 8ddd4ab1186..24711b966b5 100644
--- a/tests/ui/async-await/track-caller/async-block.rs
+++ b/tests/ui/async-await/track-caller/async-block.rs
@@ -1,9 +1,27 @@
 // edition:2021
+// revisions: afn nofeat
 
 #![feature(stmt_expr_attributes)]
+#![cfg_attr(afn, feature(async_fn_track_caller))]
 
 fn main() {
     let _ = #[track_caller] async {
         //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658]
     };
 }
+
+#[track_caller]
+async fn foo() {
+    let _ = #[track_caller] async {
+        //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658]
+    };
+}
+
+#[track_caller]
+async fn foo2() {
+    let _ = async {
+        let _ = #[track_caller] async {
+            //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658]
+        };
+    };
+}
diff --git a/tests/ui/async-await/track-caller/async-block.stderr b/tests/ui/async-await/track-caller/async-block.stderr
deleted file mode 100644
index 21d1054d220..00000000000
--- a/tests/ui/async-await/track-caller/async-block.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: `#[track_caller]` on closures is currently unstable
-  --> $DIR/async-block.rs:6:13
-   |
-LL |     let _ = #[track_caller] async {
-   |             ^^^^^^^^^^^^^^^
-   |
-   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
-   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr
new file mode 100644
index 00000000000..739c04a7673
--- /dev/null
+++ b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr
@@ -0,0 +1,57 @@
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-closure-gate.rs:8:13
+   |
+LL |     let _ = #[track_caller] async || {
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-closure-gate.rs:15:13
+   |
+LL |     let _ = #[track_caller] async || {
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-closure-gate.rs:21:13
+   |
+LL |     let _ = #[track_caller] || {
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-closure-gate.rs:28:17
+   |
+LL |         let _ = #[track_caller] || {
+   |                 ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-closure-gate.rs:36:9
+   |
+LL |         #[track_caller] || {
+   |         ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-closure-gate.rs:45:13
+   |
+LL |             #[track_caller] || {
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr
new file mode 100644
index 00000000000..739c04a7673
--- /dev/null
+++ b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr
@@ -0,0 +1,57 @@
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-closure-gate.rs:8:13
+   |
+LL |     let _ = #[track_caller] async || {
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-closure-gate.rs:15:13
+   |
+LL |     let _ = #[track_caller] async || {
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-closure-gate.rs:21:13
+   |
+LL |     let _ = #[track_caller] || {
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-closure-gate.rs:28:17
+   |
+LL |         let _ = #[track_caller] || {
+   |                 ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-closure-gate.rs:36:9
+   |
+LL |         #[track_caller] || {
+   |         ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/async-closure-gate.rs:45:13
+   |
+LL |             #[track_caller] || {
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/async-await/track-caller/async-closure-gate.rs b/tests/ui/async-await/track-caller/async-closure-gate.rs
index d9d55685599..8d8d081aa90 100644
--- a/tests/ui/async-await/track-caller/async-closure-gate.rs
+++ b/tests/ui/async-await/track-caller/async-closure-gate.rs
@@ -1,9 +1,50 @@
 // edition:2021
+// revisions: afn nofeat
 
 #![feature(async_closure, stmt_expr_attributes)]
+#![cfg_attr(afn, feature(async_fn_track_caller))]
 
 fn main() {
     let _ = #[track_caller] async || {
         //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658]
     };
 }
+
+#[track_caller]
+async fn foo() {
+    let _ = #[track_caller] async || {
+        //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658]
+    };
+}
+
+async fn foo2() {
+    let _ = #[track_caller] || {
+        //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658]
+    };
+}
+
+fn foo3() {
+    async {
+        let _ = #[track_caller] || {
+            //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658]
+        };
+    }
+}
+
+async fn foo4() {
+    let _ = || {
+        #[track_caller] || {
+            //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658]
+        };
+    };
+}
+
+fn foo5() {
+    async {
+        let _ = || {
+            #[track_caller] || {
+                //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658]
+            };
+        };
+    }
+}
diff --git a/tests/ui/async-await/track-caller/async-closure-gate.stderr b/tests/ui/async-await/track-caller/async-closure-gate.stderr
deleted file mode 100644
index 498f1b43b9b..00000000000
--- a/tests/ui/async-await/track-caller/async-closure-gate.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: `#[track_caller]` on closures is currently unstable
-  --> $DIR/async-closure-gate.rs:6:13
-   |
-LL |     let _ = #[track_caller] async || {
-   |             ^^^^^^^^^^^^^^^
-   |
-   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
-   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr
new file mode 100644
index 00000000000..f3090e3b9a6
--- /dev/null
+++ b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr
@@ -0,0 +1,31 @@
+warning: `#[track_caller]` on async functions is a no-op
+  --> $DIR/panic-track-caller.rs:53:1
+   |
+LL |   #[track_caller]
+   |   ^^^^^^^^^^^^^^^
+...
+LL | / async fn bar_track_caller() {
+LL | |     panic!()
+LL | | }
+   | |_- this function will not propagate the caller location
+   |
+   = note: see issue #110011 <https://github.com/rust-lang/rust/issues/110011> for more information
+   = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable
+   = note: `#[warn(ungated_async_fn_track_caller)]` on by default
+
+warning: `#[track_caller]` on async functions is a no-op
+  --> $DIR/panic-track-caller.rs:67:5
+   |
+LL |       #[track_caller]
+   |       ^^^^^^^^^^^^^^^
+...
+LL | /     async fn bar_assoc() {
+LL | |         panic!();
+LL | |     }
+   | |_____- this function will not propagate the caller location
+   |
+   = note: see issue #110011 <https://github.com/rust-lang/rust/issues/110011> for more information
+   = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr
index 51ea225f4cb..f3090e3b9a6 100644
--- a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr
+++ b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr
@@ -1,29 +1,31 @@
 warning: `#[track_caller]` on async functions is a no-op
-  --> $DIR/panic-track-caller.rs:50:1
+  --> $DIR/panic-track-caller.rs:53:1
    |
 LL |   #[track_caller]
    |   ^^^^^^^^^^^^^^^
+...
 LL | / async fn bar_track_caller() {
 LL | |     panic!()
 LL | | }
    | |_- this function will not propagate the caller location
    |
-   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
-   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+   = note: see issue #110011 <https://github.com/rust-lang/rust/issues/110011> for more information
+   = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable
    = note: `#[warn(ungated_async_fn_track_caller)]` on by default
 
 warning: `#[track_caller]` on async functions is a no-op
-  --> $DIR/panic-track-caller.rs:62:5
+  --> $DIR/panic-track-caller.rs:67:5
    |
 LL |       #[track_caller]
    |       ^^^^^^^^^^^^^^^
+...
 LL | /     async fn bar_assoc() {
 LL | |         panic!();
 LL | |     }
    | |_____- this function will not propagate the caller location
    |
-   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
-   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+   = note: see issue #110011 <https://github.com/rust-lang/rust/issues/110011> for more information
+   = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable
 
 warning: 2 warnings emitted
 
diff --git a/tests/ui/async-await/track-caller/panic-track-caller.rs b/tests/ui/async-await/track-caller/panic-track-caller.rs
index 65bb23e0b4b..df8290e5fff 100644
--- a/tests/ui/async-await/track-caller/panic-track-caller.rs
+++ b/tests/ui/async-await/track-caller/panic-track-caller.rs
@@ -1,9 +1,12 @@
 // run-pass
 // edition:2021
-// revisions: feat nofeat
+// revisions: afn cls nofeat
 // needs-unwind
+// gate-test-async_fn_track_caller
 #![feature(async_closure, stmt_expr_attributes)]
-#![cfg_attr(feat, feature(closure_track_caller))]
+#![cfg_attr(afn, feature(async_fn_track_caller))]
+#![cfg_attr(cls, feature(closure_track_caller))]
+#![allow(unused)]
 
 use std::future::Future;
 use std::panic;
@@ -47,7 +50,9 @@ async fn foo() {
     bar().await
 }
 
-#[track_caller] //[nofeat]~ WARN `#[track_caller]` on async functions is a no-op
+#[track_caller]
+//[cls]~^ WARN `#[track_caller]` on async functions is a no-op
+//[nofeat]~^^ WARN `#[track_caller]` on async functions is a no-op
 async fn bar_track_caller() {
     panic!()
 }
@@ -59,7 +64,9 @@ async fn foo_track_caller() {
 struct Foo;
 
 impl Foo {
-    #[track_caller] //[nofeat]~ WARN `#[track_caller]` on async functions is a no-op
+    #[track_caller]
+    //[cls]~^ WARN `#[track_caller]` on async functions is a no-op
+    //[nofeat]~^^ WARN `#[track_caller]` on async functions is a no-op
     async fn bar_assoc() {
         panic!();
     }
@@ -71,7 +78,7 @@ async fn foo_assoc() {
 
 // Since compilation is expected to fail for this fn when using
 // `nofeat`, we test that separately in `async-closure-gate.rs`
-#[cfg(feat)]
+#[cfg(cls)]
 async fn foo_closure() {
     let c = #[track_caller] async || {
         panic!();
@@ -81,7 +88,7 @@ async fn foo_closure() {
 
 // Since compilation is expected to fail for this fn when using
 // `nofeat`, we test that separately in `async-block.rs`
-#[cfg(feat)]
+#[cfg(cls)]
 async fn foo_block() {
     let a = #[track_caller] async {
         panic!();
@@ -106,21 +113,22 @@ fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 {
 }
 
 fn main() {
-    assert_eq!(panicked_at(|| block_on(foo())), 43);
+    assert_eq!(panicked_at(|| block_on(foo())), 46
+);
 
-    #[cfg(feat)]
-    assert_eq!(panicked_at(|| block_on(foo_track_caller())), 56);
-    #[cfg(nofeat)]
-    assert_eq!(panicked_at(|| block_on(foo_track_caller())), 52);
+    #[cfg(afn)]
+    assert_eq!(panicked_at(|| block_on(foo_track_caller())), 61);
+    #[cfg(any(cls, nofeat))]
+    assert_eq!(panicked_at(|| block_on(foo_track_caller())), 57);
 
-    #[cfg(feat)]
-    assert_eq!(panicked_at(|| block_on(foo_assoc())), 69);
-    #[cfg(nofeat)]
-    assert_eq!(panicked_at(|| block_on(foo_assoc())), 64);
+    #[cfg(afn)]
+    assert_eq!(panicked_at(|| block_on(foo_assoc())), 76);
+    #[cfg(any(cls, nofeat))]
+    assert_eq!(panicked_at(|| block_on(foo_assoc())), 71);
 
-    #[cfg(feat)]
-    assert_eq!(panicked_at(|| block_on(foo_closure())), 79);
+    #[cfg(cls)]
+    assert_eq!(panicked_at(|| block_on(foo_closure())), 84);
 
-    #[cfg(feat)]
-    assert_eq!(panicked_at(|| block_on(foo_block())), 89);
+    #[cfg(cls)]
+    assert_eq!(panicked_at(|| block_on(foo_block())), 96);
 }
diff --git a/tests/ui/borrowck/suggest-local-var-for-vector.stderr b/tests/ui/borrowck/suggest-local-var-for-vector.stderr
index ea92d76b4ec..c8d00f7b222 100644
--- a/tests/ui/borrowck/suggest-local-var-for-vector.stderr
+++ b/tests/ui/borrowck/suggest-local-var-for-vector.stderr
@@ -3,10 +3,10 @@ error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mu
    |
 LL |     vec[vec.len() - 1] = 123;
    |     ----^^^-----------
-   |     |   |
-   |     |   immutable borrow occurs here
+   |     |  ||
+   |     |  |immutable borrow occurs here
+   |     |  mutable borrow later used here
    |     mutable borrow occurs here
-   |     mutable borrow later used here
    |
 help: try adding a local storing this...
   --> $DIR/suggest-local-var-for-vector.rs:3:9
@@ -14,10 +14,10 @@ help: try adding a local storing this...
 LL |     vec[vec.len() - 1] = 123;
    |         ^^^^^^^^^
 help: ...and then using that local here
-  --> $DIR/suggest-local-var-for-vector.rs:3:5
+  --> $DIR/suggest-local-var-for-vector.rs:3:8
    |
 LL |     vec[vec.len() - 1] = 123;
-   |     ^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr b/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr
index 6007beb7753..368d728101c 100644
--- a/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr
+++ b/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr
@@ -3,10 +3,10 @@ error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mu
    |
 LL |     vec[vec.len() - 1] = 123;
    |     ----^^^-----------
-   |     |   |
-   |     |   immutable borrow occurs here
+   |     |  ||
+   |     |  |immutable borrow occurs here
+   |     |  mutable borrow later used here
    |     mutable borrow occurs here
-   |     mutable borrow later used here
    |
 help: try adding a local storing this...
   --> $DIR/suggest-storing-local-var-for-vector.rs:3:9
@@ -14,10 +14,10 @@ help: try adding a local storing this...
 LL |     vec[vec.len() - 1] = 123;
    |         ^^^^^^^^^
 help: ...and then using that local here
-  --> $DIR/suggest-storing-local-var-for-vector.rs:3:5
+  --> $DIR/suggest-storing-local-var-for-vector.rs:3:8
    |
 LL |     vec[vec.len() - 1] = 123;
-   |     ^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr b/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr
index efd63a08aae..e122977b9f2 100644
--- a/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr
+++ b/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr
@@ -50,42 +50,42 @@ error[E0502]: cannot borrow `i` as immutable because it is also borrowed as muta
    |
 LL |     i[i[3]] = 4;
    |     --^----
-   |     | |
-   |     | immutable borrow occurs here
+   |     |||
+   |     ||immutable borrow occurs here
+   |     |mutable borrow later used here
    |     mutable borrow occurs here
-   |     mutable borrow later used here
    |
 help: try adding a local storing this...
-  --> $DIR/two-phase-nonrecv-autoref.rs:132:7
+  --> $DIR/two-phase-nonrecv-autoref.rs:132:8
    |
 LL |     i[i[3]] = 4;
-   |       ^^^^
+   |        ^^^
 help: ...and then using that local here
-  --> $DIR/two-phase-nonrecv-autoref.rs:132:5
+  --> $DIR/two-phase-nonrecv-autoref.rs:132:6
    |
 LL |     i[i[3]] = 4;
-   |     ^^^^^^^
+   |      ^^^^^^
 
 error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable
   --> $DIR/two-phase-nonrecv-autoref.rs:138:7
    |
 LL |     i[i[3]] = i[4];
    |     --^----
-   |     | |
-   |     | immutable borrow occurs here
+   |     |||
+   |     ||immutable borrow occurs here
+   |     |mutable borrow later used here
    |     mutable borrow occurs here
-   |     mutable borrow later used here
    |
 help: try adding a local storing this...
-  --> $DIR/two-phase-nonrecv-autoref.rs:138:7
+  --> $DIR/two-phase-nonrecv-autoref.rs:138:8
    |
 LL |     i[i[3]] = i[4];
-   |       ^^^^
+   |        ^^^
 help: ...and then using that local here
-  --> $DIR/two-phase-nonrecv-autoref.rs:138:5
+  --> $DIR/two-phase-nonrecv-autoref.rs:138:6
    |
 LL |     i[i[3]] = i[4];
-   |     ^^^^^^^
+   |      ^^^^^^
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr
index cee4dfda2c9..f51f305ac38 100644
--- a/tests/ui/consts/issue-94675.stderr
+++ b/tests/ui/consts/issue-94675.stderr
@@ -7,10 +7,10 @@ LL |         self.bar[0] = baz.len();
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/issue-94675.rs:11:9
+  --> $DIR/issue-94675.rs:11:17
    |
 LL |         self.bar[0] = baz.len();
-   |         ^^^^^^^^^^^
+   |                 ^^^
    |
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
diff --git a/tests/ui/dst/issue-113447.fixed b/tests/ui/dst/issue-113447.fixed
new file mode 100644
index 00000000000..536f680f697
--- /dev/null
+++ b/tests/ui/dst/issue-113447.fixed
@@ -0,0 +1,25 @@
+// run-rustfix
+
+pub struct Bytes;
+
+impl Bytes {
+    pub fn as_slice(&self) -> &[u8] {
+        todo!()
+    }
+}
+
+impl PartialEq<[u8]> for Bytes {
+    fn eq(&self, other: &[u8]) -> bool {
+        self.as_slice() == other
+    }
+}
+
+impl PartialEq<Bytes> for &[u8] {
+    fn eq(&self, other: &Bytes) -> bool {
+        *other == **self
+    }
+}
+
+fn main() {
+    let _ = &[0u8] == &[0xAA][..]; //~ ERROR can't compare `&[u8; 1]` with `[{integer}; 1]`
+}
diff --git a/tests/ui/dst/issue-113447.rs b/tests/ui/dst/issue-113447.rs
new file mode 100644
index 00000000000..c10a4f2ff8e
--- /dev/null
+++ b/tests/ui/dst/issue-113447.rs
@@ -0,0 +1,25 @@
+// run-rustfix
+
+pub struct Bytes;
+
+impl Bytes {
+    pub fn as_slice(&self) -> &[u8] {
+        todo!()
+    }
+}
+
+impl PartialEq<[u8]> for Bytes {
+    fn eq(&self, other: &[u8]) -> bool {
+        self.as_slice() == other
+    }
+}
+
+impl PartialEq<Bytes> for &[u8] {
+    fn eq(&self, other: &Bytes) -> bool {
+        *other == **self
+    }
+}
+
+fn main() {
+    let _ = &[0u8] == [0xAA]; //~ ERROR can't compare `&[u8; 1]` with `[{integer}; 1]`
+}
diff --git a/tests/ui/dst/issue-113447.stderr b/tests/ui/dst/issue-113447.stderr
new file mode 100644
index 00000000000..240553a675b
--- /dev/null
+++ b/tests/ui/dst/issue-113447.stderr
@@ -0,0 +1,25 @@
+error[E0277]: can't compare `&[u8; 1]` with `[{integer}; 1]`
+  --> $DIR/issue-113447.rs:24:20
+   |
+LL |     let _ = &[0u8] == [0xAA];
+   |                    ^^ no implementation for `&[u8; 1] == [{integer}; 1]`
+   |
+   = help: the trait `PartialEq<[{integer}; 1]>` is not implemented for `&[u8; 1]`
+   = help: the following other types implement trait `PartialEq<Rhs>`:
+             <[A; N] as PartialEq<[B; N]>>
+             <[A; N] as PartialEq<[B]>>
+             <[A; N] as PartialEq<&[B]>>
+             <[A; N] as PartialEq<&mut [B]>>
+             <[T] as PartialEq<Vec<U, A>>>
+             <[A] as PartialEq<[B]>>
+             <[B] as PartialEq<[A; N]>>
+             <&[u8] as PartialEq<Bytes>>
+           and 4 others
+help: convert the array to a `&[u8]` slice instead
+   |
+LL |     let _ = &[0u8] == &[0xAA][..];
+   |                       +      ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dyn-star/param-env-region-infer.current.stderr b/tests/ui/dyn-star/param-env-region-infer.current.stderr
index 902053ecfef..b982be45196 100644
--- a/tests/ui/dyn-star/param-env-region-infer.current.stderr
+++ b/tests/ui/dyn-star/param-env-region-infer.current.stderr
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/param-env-region-infer.rs:18:10
+  --> $DIR/param-env-region-infer.rs:19:10
    |
 LL |     t as _
    |          ^ cannot infer type
diff --git a/tests/ui/dyn-star/param-env-region-infer.next.stderr b/tests/ui/dyn-star/param-env-region-infer.next.stderr
deleted file mode 100644
index 28aec533a00..00000000000
--- a/tests/ui/dyn-star/param-env-region-infer.next.stderr
+++ /dev/null
@@ -1,30 +0,0 @@
-error[E0391]: cycle detected when computing type of `make_dyn_star::{opaque#0}`
-  --> $DIR/param-env-region-infer.rs:16:60
-   |
-LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a {
-   |                                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires type-checking `make_dyn_star`...
-  --> $DIR/param-env-region-infer.rs:16:1
-   |
-LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing layout of `make_dyn_star::{opaque#0}`...
-   = note: ...which requires normalizing `make_dyn_star::{opaque#0}`...
-   = note: ...which again requires computing type of `make_dyn_star::{opaque#0}`, completing the cycle
-note: cycle used when checking item types in top-level module
-  --> $DIR/param-env-region-infer.rs:10:1
-   |
-LL | / #![feature(dyn_star, pointer_like_trait)]
-LL | | #![allow(incomplete_features)]
-LL | |
-LL | | use std::fmt::Debug;
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/dyn-star/param-env-region-infer.rs b/tests/ui/dyn-star/param-env-region-infer.rs
index 537473abc3a..50dec94d25b 100644
--- a/tests/ui/dyn-star/param-env-region-infer.rs
+++ b/tests/ui/dyn-star/param-env-region-infer.rs
@@ -1,9 +1,10 @@
-// revisions: current next
-// Need `-Zdeduplicate-diagnostics=yes` because the number of cycle errors
-// emitted is for some horrible reason platform-specific.
-//[next] compile-flags: -Ztrait-solver=next -Zdeduplicate-diagnostics=yes
+// revisions: current
 // incremental
 
+// FIXME(-Ztrait-solver=next): THis currently results in unstable query results:
+// `normalizes-to(opaque, opaque)` changes from `Maybe(Ambiguous)` to `Maybe(Overflow)`
+// once the hidden type of the opaque is already defined to be itself.
+
 // checks that we don't ICE if there are region inference variables in the environment
 // when computing `PointerLike` builtin candidates.
 
diff --git a/tests/ui/error-codes/E0608.stderr b/tests/ui/error-codes/E0608.stderr
index 3aec509934b..f23f9977ba0 100644
--- a/tests/ui/error-codes/E0608.stderr
+++ b/tests/ui/error-codes/E0608.stderr
@@ -1,8 +1,8 @@
 error[E0608]: cannot index into a value of type `u8`
-  --> $DIR/E0608.rs:2:5
+  --> $DIR/E0608.rs:2:8
    |
 LL |     0u8[2];
-   |     ^^^^^^
+   |        ^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/impl-trait/nested-rpit-hrtb-2.rs b/tests/ui/impl-trait/nested-rpit-hrtb-2.rs
new file mode 100644
index 00000000000..4d72962157b
--- /dev/null
+++ b/tests/ui/impl-trait/nested-rpit-hrtb-2.rs
@@ -0,0 +1,9 @@
+// The nested impl Trait references a higher-ranked region
+
+trait Trait<'a> { type Assoc; }
+impl<'a> Trait<'a> for () { type Assoc = &'a str; }
+
+fn test() -> impl for<'a> Trait<'a, Assoc = impl Sized> {}
+//~^ ERROR captures lifetime that does not appear in bounds
+
+fn main() {}
diff --git a/tests/ui/impl-trait/nested-rpit-hrtb-2.stderr b/tests/ui/impl-trait/nested-rpit-hrtb-2.stderr
new file mode 100644
index 00000000000..71d1d45f48b
--- /dev/null
+++ b/tests/ui/impl-trait/nested-rpit-hrtb-2.stderr
@@ -0,0 +1,12 @@
+error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
+  --> $DIR/nested-rpit-hrtb-2.rs:6:57
+   |
+LL | fn test() -> impl for<'a> Trait<'a, Assoc = impl Sized> {}
+   |                       --                    ----------  ^^
+   |                       |                     |
+   |                       |                     opaque type defined here
+   |                       hidden type `&'a str` captures the lifetime `'a` as defined here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/tests/ui/index-bot.rs b/tests/ui/indexing/index-bot.rs
index e69c4019f61..e69c4019f61 100644
--- a/tests/ui/index-bot.rs
+++ b/tests/ui/indexing/index-bot.rs
diff --git a/tests/ui/index-bot.stderr b/tests/ui/indexing/index-bot.stderr
index b5d78297505..bf231c92cad 100644
--- a/tests/ui/index-bot.stderr
+++ b/tests/ui/indexing/index-bot.stderr
@@ -1,8 +1,8 @@
 error[E0608]: cannot index into a value of type `!`
-  --> $DIR/index-bot.rs:2:5
+  --> $DIR/index-bot.rs:2:13
    |
 LL |     (return)[0];
-   |     ^^^^^^^^^^^
+   |             ^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/index-help.rs b/tests/ui/indexing/index-help.rs
index 66571ec41a0..66571ec41a0 100644
--- a/tests/ui/index-help.rs
+++ b/tests/ui/indexing/index-help.rs
diff --git a/tests/ui/index-help.stderr b/tests/ui/indexing/index-help.stderr
index e020d029875..e020d029875 100644
--- a/tests/ui/index-help.stderr
+++ b/tests/ui/indexing/index-help.stderr
diff --git a/tests/ui/index_message.rs b/tests/ui/indexing/index_message.rs
index 88b848d6f85..88b848d6f85 100644
--- a/tests/ui/index_message.rs
+++ b/tests/ui/indexing/index_message.rs
diff --git a/tests/ui/index_message.stderr b/tests/ui/indexing/index_message.stderr
index 56d1d70809d..80f2bd52314 100644
--- a/tests/ui/index_message.stderr
+++ b/tests/ui/indexing/index_message.stderr
@@ -1,8 +1,8 @@
 error[E0608]: cannot index into a value of type `({integer},)`
-  --> $DIR/index_message.rs:3:13
+  --> $DIR/index_message.rs:3:14
    |
 LL |     let _ = z[0];
-   |             ^^^^ help: to access tuple elements, use: `z.0`
+   |              ^^^ help: to access tuple elements, use: `.0`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/indexing-requires-a-uint.rs b/tests/ui/indexing/indexing-requires-a-uint.rs
index dbe9b44a138..dbe9b44a138 100644
--- a/tests/ui/indexing-requires-a-uint.rs
+++ b/tests/ui/indexing/indexing-requires-a-uint.rs
diff --git a/tests/ui/indexing-requires-a-uint.stderr b/tests/ui/indexing/indexing-requires-a-uint.stderr
index 7a741cfc7de..7a741cfc7de 100644
--- a/tests/ui/indexing-requires-a-uint.stderr
+++ b/tests/ui/indexing/indexing-requires-a-uint.stderr
diff --git a/tests/ui/indexing/indexing-spans-caller-location.rs b/tests/ui/indexing/indexing-spans-caller-location.rs
new file mode 100644
index 00000000000..2652f00211d
--- /dev/null
+++ b/tests/ui/indexing/indexing-spans-caller-location.rs
@@ -0,0 +1,27 @@
+// run-pass
+
+// Regression test for https://github.com/rust-lang/rust/issues/114388
+
+#[track_caller]
+fn caller_line() -> u32 {
+    std::panic::Location::caller().line()
+}
+
+fn main() {
+    let prev_line = caller_line(); // first line
+    (A { prev_line }) // second line
+    [0]; // third line
+}
+
+struct A {
+    prev_line: u32,
+}
+impl std::ops::Index<usize> for A {
+    type Output = ();
+
+    fn index(&self, _idx: usize) -> &() {
+        // Use the relative number to make it resistent to header changes.
+        assert_eq!(caller_line(), self.prev_line + 2);
+        &()
+    }
+}
diff --git a/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr b/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr
index 69c7491b2af..a0024c0920f 100644
--- a/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr
+++ b/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr
@@ -1,3 +1,3 @@
-thread 'main' panicked at $DIR/const-eval-select-backtrace-std.rs:6:6:
+thread 'main' panicked at $DIR/const-eval-select-backtrace-std.rs:6:8:
 byte index 1 is out of bounds of ``
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/invalid/issue-114435-layout-type-err.rs b/tests/ui/invalid/issue-114435-layout-type-err.rs
new file mode 100644
index 00000000000..a2d40593687
--- /dev/null
+++ b/tests/ui/invalid/issue-114435-layout-type-err.rs
@@ -0,0 +1,44 @@
+// build-fail
+// compile-flags: --crate-type lib -Cdebuginfo=2
+// error-pattern: the type has an unknown layout
+
+#![recursion_limit = "10"]
+macro_rules! link {
+    ($outer:ident, $inner:ident) => {
+        struct $outer($inner);
+        impl $outer {
+            fn new() -> $outer {
+                $outer($inner::new())
+            }
+        }
+        impl std::ops::Deref for $outer {
+            type Target = $inner;
+            fn deref(&self) -> &$inner {
+                &self.0
+            }
+        }
+    };
+}
+
+struct Bottom;
+
+impl Bottom {
+    fn new() -> Bottom {
+        Bottom
+    }
+}
+
+
+link!(A, B);
+link!(B, C);
+link!(C, D);
+link!(D, E);
+link!(E, F);
+link!(F, G);
+link!(G, H);
+link!(H, I);
+link!(I, J);
+link!(J, K);
+link!(K, Bottom);
+
+fn main() { }
diff --git a/tests/ui/invalid/issue-114435-layout-type-err.stderr b/tests/ui/invalid/issue-114435-layout-type-err.stderr
new file mode 100644
index 00000000000..a2db74ff8bd
--- /dev/null
+++ b/tests/ui/invalid/issue-114435-layout-type-err.stderr
@@ -0,0 +1,8 @@
+error: reached the recursion limit finding the struct tail for `Bottom`
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
+
+error: the type has an unknown layout
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/issues/issue-27842.stderr b/tests/ui/issues/issue-27842.stderr
index 83333aa0c47..b18fe1512b5 100644
--- a/tests/ui/issues/issue-27842.stderr
+++ b/tests/ui/issues/issue-27842.stderr
@@ -1,24 +1,24 @@
 error[E0608]: cannot index into a value of type `({integer}, {integer}, {integer})`
-  --> $DIR/issue-27842.rs:4:13
+  --> $DIR/issue-27842.rs:4:16
    |
 LL |     let _ = tup[0];
-   |             ^^^^^^ help: to access tuple elements, use: `tup.0`
+   |                ^^^ help: to access tuple elements, use: `.0`
 
 error[E0608]: cannot index into a value of type `({integer}, {integer}, {integer})`
-  --> $DIR/issue-27842.rs:9:13
+  --> $DIR/issue-27842.rs:9:16
    |
 LL |     let _ = tup[i];
-   |             ^^^^-^
+   |                ^-^
    |                 |
    |                 cannot access tuple elements at a variable index
    |
    = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`)
 
 error[E0608]: cannot index into a value of type `({integer},)`
-  --> $DIR/issue-27842.rs:14:13
+  --> $DIR/issue-27842.rs:14:16
    |
 LL |     let _ = tup[3];
-   |             ^^^^^^
+   |                ^^^
    |
    = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`)
 
diff --git a/tests/ui/issues/issue-40861.stderr b/tests/ui/issues/issue-40861.stderr
index 84e38b9bb05..9b6469d05e9 100644
--- a/tests/ui/issues/issue-40861.stderr
+++ b/tests/ui/issues/issue-40861.stderr
@@ -1,8 +1,8 @@
 error[E0608]: cannot index into a value of type `()`
-  --> $DIR/issue-40861.rs:4:5
+  --> $DIR/issue-40861.rs:4:7
    |
 LL |     ()[f(&[1.0])];
-   |     ^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^
    |
    = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`)
 
diff --git a/tests/ui/lazy-type-alias/variance.rs b/tests/ui/lazy-type-alias/variance.rs
new file mode 100644
index 00000000000..f83215856b8
--- /dev/null
+++ b/tests/ui/lazy-type-alias/variance.rs
@@ -0,0 +1,38 @@
+// This is a regression test for issue #114221.
+// Check that we compute variances for lazy type aliases.
+
+// check-pass
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+// [+] `A` is covariant over `'a`.
+struct A<'a>(Co<'a>);
+
+// [+] `Co` is covariant over `'a`.
+type Co<'a> = &'a ();
+
+fn co<'a>(x: A<'static>) {
+    let _: A<'a> = x;
+}
+
+// [-] `B` is contravariant over `'a`.
+struct B<'a>(Contra<'a>);
+
+// [-] `Contra` is contravariant over `'a`.
+type Contra<'a> = fn(&'a ());
+
+fn contra<'a>(x: B<'a>) {
+    let _: B<'static> = x;
+}
+
+struct C<T, U>(CoContra<T, U>);
+
+// [+, -] `CoContra` is covariant over `T` and contravariant over `U`.
+type CoContra<T, U> = Option<(T, fn(U))>;
+
+fn co_contra<'a>(x: C<&'static (), &'a ()>) -> C<&'a (), &'static ()> {
+    x
+}
+
+fn main() {}
diff --git a/tests/ui/lint/lint-unconditional-recursion.stderr b/tests/ui/lint/lint-unconditional-recursion.stderr
index 9d200a7898e..d75754bf9f9 100644
--- a/tests/ui/lint/lint-unconditional-recursion.stderr
+++ b/tests/ui/lint/lint-unconditional-recursion.stderr
@@ -139,7 +139,7 @@ error: function cannot return without recursing
 LL |     fn index(&self, x: usize) -> &Baz {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
 LL |         &self[x]
-   |          ------- recursive call site
+   |              --- recursive call site
    |
    = help: a `loop` may express intention better if this is on purpose
 
diff --git a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
index e7da825ae36..b2d8a28d3c4 100644
--- a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
+++ b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
@@ -5,8 +5,8 @@ const s: usize = 42;
 const s_s: usize = 42;
 
 fn main() {
-    let s = "rust"; //~ ERROR identifier pair considered confusable
-    let s_s = "rust2"; //~ ERROR identifier pair considered confusable
+    let s = "rust"; //~ ERROR found both
+    let s_s = "rust2"; //~ ERROR found both
     not_affected();
 }
 
diff --git a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr
index e9906c83d12..d1920f215e2 100644
--- a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr
+++ b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr
@@ -1,11 +1,11 @@
-error: identifier pair considered confusable between `s` and `s`
+error: found both `s` and `s` as identifiers, which look alike
   --> $DIR/lint-confusable-idents.rs:8:9
    |
 LL | const s: usize = 42;
-   |       -- this is where the previous identifier occurred
+   |       -- other identifier used here
 ...
 LL |     let s = "rust";
-   |         ^
+   |         ^ this identifier can be confused with `s`
    |
 note: the lint level is defined here
   --> $DIR/lint-confusable-idents.rs:1:9
@@ -13,14 +13,14 @@ note: the lint level is defined here
 LL | #![deny(confusable_idents)]
    |         ^^^^^^^^^^^^^^^^^
 
-error: identifier pair considered confusable between `s_s` and `s_s`
+error: found both `s_s` and `s_s` as identifiers, which look alike
   --> $DIR/lint-confusable-idents.rs:9:9
    |
 LL | const s_s: usize = 42;
-   |       --- this is where the previous identifier occurred
+   |       --- other identifier used here
 ...
 LL |     let s_s = "rust2";
-   |         ^^^^^
+   |         ^^^^^ this identifier can be confused with `s_s`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/moves/use_of_moved_value_clone_suggestions.stderr b/tests/ui/moves/use_of_moved_value_clone_suggestions.stderr
index 22e7951dbe3..0bb486a8893 100644
--- a/tests/ui/moves/use_of_moved_value_clone_suggestions.stderr
+++ b/tests/ui/moves/use_of_moved_value_clone_suggestions.stderr
@@ -8,7 +8,7 @@ LL |     (t, t)
    |      |
    |      value moved here
    |
-help: consider cloning the value if the performance cost is acceptable
+help: clone the value to increment its reference count
    |
 LL |     (t.clone(), t)
    |       ++++++++
diff --git a/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr b/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr
index d1052ce3508..5f8076fc84d 100644
--- a/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr
+++ b/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `Sealed`
    |
 LL |     pub trait Sealed: self::b::Hidden {
    |                       ^^^^^^^^^^^^^^^ required by this bound in `Sealed`
-   = note: `Sealed` is a "sealed trait", because to implement it you also need to implelement `a::b::Hidden`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it
+   = note: `Sealed` is a "sealed trait", because to implement it you also need to implement `a::b::Hidden`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it
 
 error: aborting due to previous error
 
diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout
index 4a2200091b2..e476a8024fd 100644
--- a/tests/ui/proc-macro/meta-macro-hygiene.stdout
+++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout
@@ -18,7 +18,7 @@ Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro
 use core /* 0#1 */::prelude /* 0#1 */::rust_2018 /* 0#1 */::*;
 #[macro_use /* 0#1 */]
 extern crate core /* 0#1 */;
-extern crate compiler_builtins /* 443 */ as _ /* 0#1 */;
+extern crate compiler_builtins /* 444 */ as _ /* 0#1 */;
 // Don't load unnecessary hygiene information from std
 extern crate std /* 0#0 */;
 
diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
index 077a728a7a6..23a21004238 100644
--- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
+++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
@@ -39,7 +39,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
 use ::core /* 0#1 */::prelude /* 0#1 */::rust_2015 /* 0#1 */::*;
 #[macro_use /* 0#1 */]
 extern crate core /* 0#2 */;
-extern crate compiler_builtins /* 443 */ as _ /* 0#2 */;
+extern crate compiler_builtins /* 444 */ as _ /* 0#2 */;
 // Don't load unnecessary hygiene information from std
 extern crate std /* 0#0 */;
 
diff --git a/tests/ui/span/suggestion-non-ascii.stderr b/tests/ui/span/suggestion-non-ascii.stderr
index b14632d4e1b..21f8bb62a0c 100644
--- a/tests/ui/span/suggestion-non-ascii.stderr
+++ b/tests/ui/span/suggestion-non-ascii.stderr
@@ -1,8 +1,8 @@
 error[E0608]: cannot index into a value of type `({integer},)`
-  --> $DIR/suggestion-non-ascii.rs:3:21
+  --> $DIR/suggestion-non-ascii.rs:3:24
    |
 LL |     println!("☃{}", tup[0]);
-   |                     ^^^^^^ help: to access tuple elements, use: `tup.0`
+   |                        ^^^ help: to access tuple elements, use: `.0`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.rs b/tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.rs
new file mode 100644
index 00000000000..fcafdcf637a
--- /dev/null
+++ b/tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.rs
@@ -0,0 +1,32 @@
+// compile-flags: -Ztrait-solver=next
+
+// Proving `W<?0>: Trait` instantiates `?0` with `(W<?1>, W<?2>)` and then
+// proves `W<?1>: Trait` and `W<?2>: Trait`, resulting in a coinductive cycle.
+//
+// Proving coinductive cycles runs until we reach a fixpoint. This fixpoint is
+// never reached here and each step doubles the amount of nested obligations.
+//
+// This previously caused a hang in the trait solver, see
+// https://github.com/rust-lang/trait-system-refactor-initiative/issues/13.
+
+#![feature(rustc_attrs)]
+
+#[rustc_coinductive]
+trait Trait {}
+
+struct W<T>(T);
+
+impl<T, U> Trait for W<(W<T>, W<U>)>
+where
+    W<T>: Trait,
+    W<U>: Trait,
+{
+}
+
+fn impls<T: Trait>() {}
+
+fn main() {
+    impls::<W<_>>();
+    //~^ ERROR type annotations needed
+    //~| ERROR overflow evaluating the requirement
+}
diff --git a/tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.stderr b/tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.stderr
new file mode 100644
index 00000000000..7d3535e1f01
--- /dev/null
+++ b/tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.stderr
@@ -0,0 +1,23 @@
+error[E0282]: type annotations needed
+  --> $DIR/fixpoint-exponential-growth.rs:29:5
+   |
+LL |     impls::<W<_>>();
+   |     ^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls`
+
+error[E0275]: overflow evaluating the requirement `W<_>: Trait`
+  --> $DIR/fixpoint-exponential-growth.rs:29:5
+   |
+LL |     impls::<W<_>>();
+   |     ^^^^^^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`fixpoint_exponential_growth`)
+note: required by a bound in `impls`
+  --> $DIR/fixpoint-exponential-growth.rs:26:13
+   |
+LL | fn impls<T: Trait>() {}
+   |             ^^^^^ required by this bound in `impls`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0275, E0282.
+For more information about an error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.rs b/tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.rs
new file mode 100644
index 00000000000..0cd14f05c8d
--- /dev/null
+++ b/tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.rs
@@ -0,0 +1,69 @@
+// compile-flags: -Ztrait-solver=next
+#![feature(rustc_attrs)]
+
+// This test is incredibly subtle. At its core the goal is to get a coinductive cycle,
+// which, depending on its root goal, either holds or errors. We achieve this by getting
+// incomplete inference via a `ParamEnv` candidate in the `A<T>` impl and required
+// inference from an `Impl` candidate in the `B<T>` impl.
+//
+// To make global cache accesses stronger than the guidance from the where-bounds, we add
+// another coinductive cycle from `A<T>: Trait<U, V, D>` to `A<T>: Trait<U, D, V>` and only
+// constrain `D` directly. This means that any candidates which rely on `V` only make
+// progress in the second iteration, allowing a cache access in the first iteration to take
+// precedence.
+//
+// tl;dr: our caching of coinductive cycles was broken and this is a regression
+// test for that.
+
+#[rustc_coinductive]
+trait Trait<T: ?Sized, V: ?Sized, D: ?Sized> {}
+struct A<T: ?Sized>(*const T);
+struct B<T: ?Sized>(*const T);
+
+trait IncompleteGuidance<T: ?Sized, V: ?Sized> {}
+impl<T: ?Sized, U: ?Sized + 'static> IncompleteGuidance<U, u8> for T {}
+impl<T: ?Sized, U: ?Sized + 'static> IncompleteGuidance<U, i8> for T {}
+impl<T: ?Sized, U: ?Sized + 'static> IncompleteGuidance<U, i16> for T {}
+
+trait ImplGuidance<T: ?Sized, V: ?Sized> {}
+impl<T: ?Sized> ImplGuidance<u32, u8> for T {}
+impl<T: ?Sized> ImplGuidance<i32, i8> for T {}
+
+impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
+where
+    T: IncompleteGuidance<U, V>,
+    A<T>: Trait<U, D, V>,
+    B<T>: Trait<U, V, D>,
+    (): ToU8<D>,
+{
+}
+
+trait ToU8<T: ?Sized> {}
+impl ToU8<u8> for () {}
+
+impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for B<T>
+where
+    T: ImplGuidance<U, V>,
+    A<T>: Trait<U, V, D>,
+{
+}
+
+fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
+
+fn with_bound<X>()
+where
+    X: IncompleteGuidance<i32, u8>,
+    X: IncompleteGuidance<u32, i8>,
+    X: IncompleteGuidance<u32, i16>,
+{
+    impls_trait::<B<X>, _, _, _>(); // entering the cycle from `B` works
+
+    // entering the cycle from `A` fails, but would work if we were to use the cache
+    // result of `B<X>`.
+    impls_trait::<A<X>, _, _, _>();
+    //~^ ERROR the trait bound `A<X>: Trait<_, _, _>` is not satisfied
+}
+
+fn main() {
+    with_bound::<u32>();
+}
diff --git a/tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.stderr b/tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.stderr
new file mode 100644
index 00000000000..f1871ff0564
--- /dev/null
+++ b/tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.stderr
@@ -0,0 +1,16 @@
+error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
+  --> $DIR/incompleteness-unstable-result.rs:63:19
+   |
+LL |     impls_trait::<A<X>, _, _, _>();
+   |                   ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`
+   |
+   = help: the trait `Trait<U, V, D>` is implemented for `A<T>`
+note: required by a bound in `impls_trait`
+  --> $DIR/incompleteness-unstable-result.rs:51:28
+   |
+LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
+   |                            ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/new-solver/overflow/global-cache.rs b/tests/ui/traits/new-solver/overflow/global-cache.rs
new file mode 100644
index 00000000000..adc03da04a8
--- /dev/null
+++ b/tests/ui/traits/new-solver/overflow/global-cache.rs
@@ -0,0 +1,23 @@
+// compile-flags: -Ztrait-solver=next
+
+// Check that we consider the reached depth of global cache
+// entries when detecting overflow. We would otherwise be unstable
+// wrt to incremental compilation.
+#![recursion_limit = "9"]
+
+trait Trait {}
+
+struct Inc<T>(T);
+
+impl<T: Trait> Trait for Inc<T> {}
+impl Trait for () {}
+
+fn impls_trait<T: Trait>() {}
+
+type Four<T> = Inc<Inc<Inc<Inc<T>>>>;
+
+fn main() {
+    impls_trait::<Four<Four<()>>>();
+    impls_trait::<Four<Four<Four<Four<()>>>>>();
+    //~^ ERROR overflow evaluating the requirement
+}
diff --git a/tests/ui/traits/new-solver/overflow/global-cache.stderr b/tests/ui/traits/new-solver/overflow/global-cache.stderr
new file mode 100644
index 00000000000..f3b86a083ad
--- /dev/null
+++ b/tests/ui/traits/new-solver/overflow/global-cache.stderr
@@ -0,0 +1,16 @@
+error[E0275]: overflow evaluating the requirement `Inc<Inc<Inc<Inc<Inc<Inc<Inc<...>>>>>>>: Trait`
+  --> $DIR/global-cache.rs:21:5
+   |
+LL |     impls_trait::<Four<Four<Four<Four<()>>>>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "18"]` attribute to your crate (`global_cache`)
+note: required by a bound in `impls_trait`
+  --> $DIR/global-cache.rs:15:19
+   |
+LL | fn impls_trait<T: Trait>() {}
+   |                   ^^^^^ required by this bound in `impls_trait`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/trait-upcasting/fewer-associated.rs b/tests/ui/traits/trait-upcasting/fewer-associated.rs
new file mode 100644
index 00000000000..8228eea2681
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/fewer-associated.rs
@@ -0,0 +1,25 @@
+// check-pass
+// issue: 114035
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
+
+#![feature(trait_upcasting)]
+
+trait A: B {
+    type Assoc;
+}
+
+trait B {}
+
+fn upcast(a: &dyn A<Assoc = i32>) -> &dyn B {
+    a
+}
+
+// Make sure that we can drop the existential projection `A::Assoc = i32`
+// when upcasting `dyn A<Assoc = i32>` to `dyn B`. Before, we used some
+// complicated algorithm which required rebuilding a new object type with
+// different bounds in order to test that an upcast was valid, but this
+// didn't allow upcasting to t that have fewer associated types
+// than the source type.
+
+fn main() {}
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr
new file mode 100644
index 00000000000..59c9d573705
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/illegal-upcast-from-impl.rs:16:66
+   |
+LL | fn illegal(x: &dyn Sub<Assoc = ()>) -> &dyn Super<Assoc = i32> { x }
+   |                                        -----------------------   ^ expected trait `Super`, found trait `Sub`
+   |                                        |
+   |                                        expected `&dyn Super<Assoc = i32>` because of return type
+   |
+   = note: expected reference `&dyn Super<Assoc = i32>`
+              found reference `&dyn Sub<Assoc = ()>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr
new file mode 100644
index 00000000000..59c9d573705
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/illegal-upcast-from-impl.rs:16:66
+   |
+LL | fn illegal(x: &dyn Sub<Assoc = ()>) -> &dyn Super<Assoc = i32> { x }
+   |                                        -----------------------   ^ expected trait `Super`, found trait `Sub`
+   |                                        |
+   |                                        expected `&dyn Super<Assoc = i32>` because of return type
+   |
+   = note: expected reference `&dyn Super<Assoc = i32>`
+              found reference `&dyn Sub<Assoc = ()>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs
new file mode 100644
index 00000000000..774474281ea
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs
@@ -0,0 +1,23 @@
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
+
+#![feature(trait_upcasting)]
+
+trait Super {
+    type Assoc;
+}
+
+trait Sub: Super {}
+
+impl<T: ?Sized> Super for T {
+    type Assoc = i32;
+}
+
+fn illegal(x: &dyn Sub<Assoc = ()>) -> &dyn Super<Assoc = i32> { x }
+//~^ ERROR mismatched types
+
+// Want to make sure that we can't "upcast" to a supertrait that has a different
+// associated type that is instead provided by a blanket impl (and doesn't come
+// from the object bounds).
+
+fn main() {}
diff --git a/tests/ui/traits/trait-upcasting/normalization.rs b/tests/ui/traits/trait-upcasting/normalization.rs
new file mode 100644
index 00000000000..c78338b0da9
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/normalization.rs
@@ -0,0 +1,20 @@
+// check-pass
+// issue: 114113
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
+
+#![feature(trait_upcasting)]
+
+trait Mirror {
+    type Assoc;
+}
+impl<T> Mirror for T {
+    type Assoc = T;
+}
+
+trait Bar<T> {}
+trait Foo<T>: Bar<<T as Mirror>::Assoc> {}
+
+fn upcast<T>(x: &dyn Foo<T>) -> &dyn Bar<T> { x }
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs
index 2c740ccc1ae..fdd8fa65bd0 100644
--- a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs
+++ b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs
@@ -1,5 +1,7 @@
 #![feature(type_alias_impl_trait)]
 // check-pass
+// revisions: default edition2021
+//[edition2021] compile-flags: --edition 2021
 
 fn main() {
     type T = impl Copy;
diff --git a/tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs
new file mode 100644
index 00000000000..4a9631a7208
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs
@@ -0,0 +1,15 @@
+#![feature(type_alias_impl_trait)]
+
+trait Trait<'a> { type Assoc; }
+impl<'a> Trait<'a> for () { type Assoc = &'a str; }
+
+type WithoutLt = impl Sized;
+fn without_lt() -> impl for<'a> Trait<'a, Assoc = WithoutLt> {}
+//~^ ERROR captures lifetime that does not appear in bounds
+
+type WithLt<'a> = impl Sized + 'a;
+//~^ ERROR concrete type differs from previous defining opaque type use
+fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {}
+//~^ ERROR expected generic lifetime parameter, found `'a`
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr
new file mode 100644
index 00000000000..9a783a6d92a
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr
@@ -0,0 +1,35 @@
+error[E0700]: hidden type for `WithoutLt` captures lifetime that does not appear in bounds
+  --> $DIR/nested-tait-hrtb.rs:7:62
+   |
+LL | type WithoutLt = impl Sized;
+   |                  ---------- opaque type defined here
+LL | fn without_lt() -> impl for<'a> Trait<'a, Assoc = WithoutLt> {}
+   |                             --                               ^^
+   |                             |
+   |                             hidden type `&'a str` captures the lifetime `'a` as defined here
+
+error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/nested-tait-hrtb.rs:12:60
+   |
+LL | type WithLt<'a> = impl Sized + 'a;
+   |             -- this generic parameter must be used with a generic lifetime parameter
+LL |
+LL | fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {}
+   |                                                            ^^
+
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/nested-tait-hrtb.rs:10:19
+   |
+LL | type WithLt<'a> = impl Sized + 'a;
+   |                   ^^^^^^^^^^^^^^^ expected `&'a str`, got `{type error}`
+   |
+note: previous use here
+  --> $DIR/nested-tait-hrtb.rs:12:17
+   |
+LL | fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {}
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0700, E0792.
+For more information about an error, try `rustc --explain E0700`.
diff --git a/tests/ui/typeck/issue-112252-ptr-arithmetics-help.stderr b/tests/ui/typeck/issue-112252-ptr-arithmetics-help.stderr
index c55930da225..f81736245f3 100644
--- a/tests/ui/typeck/issue-112252-ptr-arithmetics-help.stderr
+++ b/tests/ui/typeck/issue-112252-ptr-arithmetics-help.stderr
@@ -38,10 +38,10 @@ LL |     let _c = unsafe { _ptr2.offset_from(_ptr1) };
    |              ++++++++      ~~~~~~~~~~~~~     +++
 
 error[E0608]: cannot index into a value of type `*const u32`
-  --> $DIR/issue-112252-ptr-arithmetics-help.rs:9:14
+  --> $DIR/issue-112252-ptr-arithmetics-help.rs:9:19
    |
 LL |     let _d = _ptr1[5];
-   |              ^^^^^^^^
+   |                   ^^^
    |
 help: consider using `wrapping_add` or `add` for indexing into raw pointer
    |
diff --git a/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.rs b/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.rs
new file mode 100644
index 00000000000..da2dae1c46b
--- /dev/null
+++ b/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.rs
@@ -0,0 +1,15 @@
+struct RGB {
+    g: f64,
+    b: f64,
+}
+
+fn main() {
+    let (r, alone_in_path, b): (f32, f32, f32) = (e.clone(), e.clone());
+    //~^ ERROR cannot find value `e` in this scope
+    //~| ERROR cannot find value `e` in this scope
+    //~| ERROR mismatched types
+    let _ = RGB { r, g, b };
+    //~^ ERROR cannot find value `g` in this scope
+    //~| ERROR struct `RGB` has no field named `r`
+    //~| ERROR mismatched types
+}
diff --git a/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.stderr b/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.stderr
new file mode 100644
index 00000000000..4ccfacfb005
--- /dev/null
+++ b/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.stderr
@@ -0,0 +1,52 @@
+error[E0425]: cannot find value `e` in this scope
+  --> $DIR/issue-114423-ice-regression-in-suggestion.rs:7:51
+   |
+LL |     let (r, alone_in_path, b): (f32, f32, f32) = (e.clone(), e.clone());
+   |                                                   ^ not found in this scope
+
+error[E0425]: cannot find value `e` in this scope
+  --> $DIR/issue-114423-ice-regression-in-suggestion.rs:7:62
+   |
+LL |     let (r, alone_in_path, b): (f32, f32, f32) = (e.clone(), e.clone());
+   |                                                              ^ not found in this scope
+
+error[E0425]: cannot find value `g` in this scope
+  --> $DIR/issue-114423-ice-regression-in-suggestion.rs:11:22
+   |
+LL |     let _ = RGB { r, g, b };
+   |                      ^ help: a local variable with a similar name exists: `b`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-114423-ice-regression-in-suggestion.rs:7:50
+   |
+LL |     let (r, alone_in_path, b): (f32, f32, f32) = (e.clone(), e.clone());
+   |                                ---------------   ^^^^^^^^^^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 2 elements
+   |                                |
+   |                                expected due to this
+   |
+   = note: expected tuple `(f32, f32, f32)`
+              found tuple `(f32, f32)`
+
+error[E0560]: struct `RGB` has no field named `r`
+  --> $DIR/issue-114423-ice-regression-in-suggestion.rs:11:19
+   |
+LL |     let _ = RGB { r, g, b };
+   |                   ^ `RGB` does not have this field
+   |
+   = note: all struct fields are already assigned
+
+error[E0308]: mismatched types
+  --> $DIR/issue-114423-ice-regression-in-suggestion.rs:11:25
+   |
+LL |     let _ = RGB { r, g, b };
+   |                         ^ expected `f64`, found `f32`
+   |
+help: you can convert an `f32` to an `f64`
+   |
+LL |     let _ = RGB { r, g, b: b.into() };
+   |                         ++  +++++++
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0425, E0560.
+For more information about an error, try `rustc --explain E0308`.