about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorBoxy <rust@boxyuwu.dev>2025-01-28 11:57:19 +0000
committerBoxy <rust@boxyuwu.dev>2025-01-28 11:57:19 +0000
commit815c5d4eee36e836c7b75aa9288a58c4e8e7830b (patch)
treed4e7e89bcb0f3fd8e1ad2004c2c4a3dab933aaed /compiler
parent62102ee041d0681e507e16c6d17ff5798b3a9d9f (diff)
parent66d6064f9eb888018775e08f84747ee6f39ba28e (diff)
Merge from rustc
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/ast.rs44
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs2
-rw-r--r--compiler/rustc_ast/src/entry.rs10
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs8
-rw-r--r--compiler/rustc_ast/src/util/comments.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/delegation.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs81
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs1
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs40
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs24
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs4
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs14
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs16
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs2
-rw-r--r--compiler/rustc_borrowck/messages.ftl3
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs16
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs27
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs4
-rw-r--r--compiler/rustc_borrowck/src/polonius/dump.rs181
-rw-r--r--compiler/rustc_borrowck/src/session_diagnostics.rs13
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs11
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/tests.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch44
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch15
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0028-coretests-Disable-long-running-tests.patch6
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh5
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs22
-rw-r--r--compiler/rustc_codegen_cranelift/src/cast.rs22
-rw-r--r--compiler/rustc_codegen_cranelift/src/codegen_i128.rs30
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs12
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs21
-rw-r--r--compiler/rustc_codegen_gcc/.github/workflows/ci.yml10
-rw-r--r--compiler/rustc_codegen_gcc/.github/workflows/failures.yml6
-rw-r--r--compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml2
-rw-r--r--compiler/rustc_codegen_gcc/.github/workflows/m68k.yml8
-rw-r--r--compiler/rustc_codegen_gcc/.github/workflows/release.yml13
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/build.rs10
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/config.rs57
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/info.rs4
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/main.rs4
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/test.rs33
-rw-r--r--compiler/rustc_codegen_gcc/example/alloc_example.rs7
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs2
-rw-r--r--compiler/rustc_codegen_gcc/example/mod_bench.rs36
-rw-r--r--compiler/rustc_codegen_gcc/libgccjit.version2
-rw-r--r--compiler/rustc_codegen_gcc/messages.ftl3
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs5
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs1
-rw-r--r--compiler/rustc_codegen_gcc/src/debuginfo.rs18
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/abort1.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/abort2.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/array.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/assign.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/closure.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/condition.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/empty_main.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/exit.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/exit_code.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/mut_ref.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/operations.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/return-tuple.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/slice.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/static.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/structs.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/tuple.rs7
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs17
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs150
-rw-r--r--compiler/rustc_codegen_llvm/src/builder/autodiff.rs25
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs58
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs59
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs28
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs209
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs21
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs13
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml3
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl4
-rw-r--r--compiler/rustc_codegen_ssa/src/assert_module_sources.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/back/command.rs17
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs77
-rw-r--r--compiler/rustc_codegen_ssa/src/back/lto.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs24
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs62
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs22
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/naked_asm.rs173
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs59
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs73
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs21
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/consts.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/write.rs2
-rw-r--r--compiler/rustc_const_eval/messages.ftl2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs2
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-rw-r--r--compiler/rustc_data_structures/src/flock/windows.rs4
-rw-r--r--compiler/rustc_data_structures/src/graph/mod.rs16
-rw-r--r--compiler/rustc_data_structures/src/graph/scc/mod.rs4
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml2
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs152
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0038.md6
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0132.md33
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0138.md26
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0393.md12
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0433.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0647.md14
-rw-r--r--compiler/rustc_error_codes/src/lib.rs4
-rw-r--r--compiler/rustc_errors/Cargo.toml2
-rw-r--r--compiler/rustc_errors/src/emitter.rs2
-rw-r--r--compiler/rustc_errors/src/json.rs50
-rw-r--r--compiler/rustc_errors/src/json/tests.rs2
-rw-r--r--compiler/rustc_errors/src/lib.rs3
-rw-r--r--compiler/rustc_expand/src/config.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs20
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs9
-rw-r--r--compiler/rustc_feature/src/removed.rs7
-rw-r--r--compiler/rustc_feature/src/unstable.rs4
-rw-r--r--compiler/rustc_hir/src/def.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs229
-rw-r--r--compiler/rustc_hir/src/hir/tests.rs83
-rw-r--r--compiler/rustc_hir/src/intravisit.rs226
-rw-r--r--compiler/rustc_hir/src/lang_items.rs4
-rw-r--r--compiler/rustc_hir/src/lib.rs2
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl23
-rw-r--r--compiler/rustc_hir_analysis/src/autoderef.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs83
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs48
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs122
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs74
-rw-r--r--compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs211
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs70
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs29
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs22
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs19
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs1
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs38
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs35
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs23
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs27
-rw-r--r--compiler/rustc_index/src/interval.rs2
-rw-r--r--compiler/rustc_infer/src/infer/context.rs2
-rw-r--r--compiler/rustc_infer/src/infer/relate/higher_ranked.rs6
-rw-r--r--compiler/rustc_interface/src/interface.rs33
-rw-r--r--compiler/rustc_interface/src/tests.rs9
-rw-r--r--compiler/rustc_lint/messages.ftl16
-rw-r--r--compiler/rustc_lint/src/builtin.rs95
-rw-r--r--compiler/rustc_lint/src/dangling.rs2
-rw-r--r--compiler/rustc_lint/src/early/diagnostics.rs1
-rw-r--r--compiler/rustc_lint/src/early/diagnostics/check_cfg.rs29
-rw-r--r--compiler/rustc_lint/src/expect.rs2
-rw-r--r--compiler/rustc_lint/src/if_let_rescope.rs11
-rw-r--r--compiler/rustc_lint/src/internal.rs6
-rw-r--r--compiler/rustc_lint/src/late.rs9
-rw-r--r--compiler/rustc_lint/src/lib.rs1
-rw-r--r--compiler/rustc_lint/src/lints.rs50
-rw-r--r--compiler/rustc_lint/src/non_local_def.rs6
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs2
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs4
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs7
-rw-r--r--compiler/rustc_lint/src/passes.rs2
-rw-r--r--compiler/rustc_lint/src/traits.rs8
-rw-r--r--compiler/rustc_lint/src/types.rs141
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs81
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs15
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp182
-rw-r--r--compiler/rustc_metadata/messages.ftl3
-rw-r--r--compiler/rustc_metadata/src/creader.rs10
-rw-r--r--compiler/rustc_metadata/src/errors.rs7
-rw-r--r--compiler/rustc_middle/messages.ftl3
-rw-r--r--compiler/rustc_middle/src/error.rs3
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs5
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/lint.rs6
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs2
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs11
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs28
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs4
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs4
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs8
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs63
-rw-r--r--compiler/rustc_middle/src/mir/query.rs68
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs9
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs6
-rw-r--r--compiler/rustc_middle/src/query/arena_cached.rs47
-rw-r--r--compiler/rustc_middle/src/query/erase.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs16
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs20
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs145
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs20
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs2
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs14
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs9
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/util.rs9
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs3
-rw-r--r--compiler/rustc_middle/src/values.rs10
-rw-r--r--compiler/rustc_mir_build/messages.ftl2
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/mod.rs11
-rw-r--r--compiler/rustc_mir_build/src/builder/scope.rs9
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs2
-rw-r--r--compiler/rustc_mir_build/src/errors.rs14
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs16
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs2
-rw-r--r--compiler/rustc_mir_transform/src/abort_unwinding_calls.rs4
-rw-r--r--compiler/rustc_mir_transform/src/add_call_guards.rs4
-rw-r--r--compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs4
-rw-r--r--compiler/rustc_mir_transform/src/add_retag.rs4
-rw-r--r--compiler/rustc_mir_transform/src/add_subtyping_projections.rs4
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs4
-rw-r--r--compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs4
-rw-r--r--compiler/rustc_mir_transform/src/copy_prop.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs20
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters/balanced_flow.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters/iter_nodes.rs16
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs183
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters/node_flow/tests.rs20
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters/union_find.rs28
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs36
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs12
-rw-r--r--compiler/rustc_mir_transform/src/cross_crate_inline.rs2
-rw-r--r--compiler/rustc_mir_transform/src/ctfe_limit.rs4
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs4
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs4
-rw-r--r--compiler/rustc_mir_transform/src/deduplicate_blocks.rs4
-rw-r--r--compiler/rustc_mir_transform/src/deref_separator.rs4
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs4
-rw-r--r--compiler/rustc_mir_transform/src/dump_mir.rs4
-rw-r--r--compiler/rustc_mir_transform/src/early_otherwise_branch.rs4
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_box_derefs.rs4
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs4
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs4
-rw-r--r--compiler/rustc_mir_transform/src/function_item_references.rs4
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs22
-rw-r--r--compiler/rustc_mir_transform/src/impossible_predicates.rs4
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs8
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs6
-rw-r--r--compiler/rustc_mir_transform/src/jump_threading.rs4
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs4
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs33
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs4
-rw-r--r--compiler/rustc_mir_transform/src/lower_slice_len.rs4
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs4
-rw-r--r--compiler/rustc_mir_transform/src/mentioned_items.rs4
-rw-r--r--compiler/rustc_mir_transform/src/multiple_return_terminators.rs4
-rw-r--r--compiler/rustc_mir_transform/src/nrvo.rs4
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs39
-rw-r--r--compiler/rustc_mir_transform/src/post_analysis_normalize.rs4
-rw-r--r--compiler/rustc_mir_transform/src/prettify.rs8
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs4
-rw-r--r--compiler/rustc_mir_transform/src/ref_prop.rs4
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs4
-rw-r--r--compiler/rustc_mir_transform/src/remove_place_mention.rs4
-rw-r--r--compiler/rustc_mir_transform/src/remove_storage_markers.rs4
-rw-r--r--compiler/rustc_mir_transform/src/remove_uninit_drops.rs4
-rw-r--r--compiler/rustc_mir_transform/src/remove_unneeded_drops.rs4
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs4
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs1
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs8
-rw-r--r--compiler/rustc_mir_transform/src/simplify_branches.rs4
-rw-r--r--compiler/rustc_mir_transform/src/simplify_comparison_integral.rs4
-rw-r--r--compiler/rustc_mir_transform/src/single_use_consts.rs4
-rw-r--r--compiler/rustc_mir_transform/src/sroa.rs4
-rw-r--r--compiler/rustc_mir_transform/src/strip_debuginfo.rs4
-rw-r--r--compiler/rustc_mir_transform/src/unreachable_enum_branching.rs4
-rw-r--r--compiler/rustc_mir_transform/src/unreachable_prop.rs4
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs4
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs17
-rw-r--r--compiler/rustc_next_trait_solver/Cargo.toml1
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs42
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs48
-rw-r--r--compiler/rustc_parse/src/errors.rs2
-rw-r--r--compiler/rustc_parse/src/lib.rs67
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs4
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs65
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs8
-rw-r--r--compiler/rustc_parse_format/src/lib.rs10
-rw-r--r--compiler/rustc_passes/messages.ftl8
-rw-r--r--compiler/rustc_passes/src/check_attr.rs41
-rw-r--r--compiler/rustc_passes/src/dead.rs4
-rw-r--r--compiler/rustc_passes/src/entry.rs27
-rw-r--r--compiler/rustc_passes/src/errors.rs15
-rw-r--r--compiler/rustc_passes/src/input_stats.rs7
-rw-r--r--compiler/rustc_passes/src/liveness.rs16
-rw-r--r--compiler/rustc_passes/src/stability.rs13
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs4
-rw-r--r--compiler/rustc_privacy/messages.ftl18
-rw-r--r--compiler/rustc_privacy/src/errors.rs14
-rw-r--r--compiler/rustc_privacy/src/lib.rs173
-rw-r--r--compiler/rustc_query_system/src/query/job.rs6
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs54
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs549
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs59
-rw-r--r--compiler/rustc_resolve/src/errors.rs16
-rw-r--r--compiler/rustc_resolve/src/ident.rs98
-rw-r--r--compiler/rustc_resolve/src/imports.rs261
-rw-r--r--compiler/rustc_resolve/src/late.rs237
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs11
-rw-r--r--compiler/rustc_resolve/src/lib.rs16
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs5
-rw-r--r--compiler/rustc_session/Cargo.toml2
-rw-r--r--compiler/rustc_session/src/config.rs15
-rw-r--r--compiler/rustc_session/src/filesearch.rs2
-rw-r--r--compiler/rustc_session/src/session.rs13
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs15
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mod.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs42
-rw-r--r--compiler/rustc_span/src/lib.rs55
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_target/src/callconv/powerpc64.rs4
-rw-r--r--compiler/rustc_target/src/callconv/s390x.rs14
-rw-r--r--compiler/rustc_target/src/callconv/x86_win64.rs20
-rw-r--r--compiler/rustc_target/src/spec/base/nto_qnx.rs97
-rw-r--r--compiler/rustc_target/src/spec/base/windows_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/base/windows_gnullvm.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs9
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx700.rs42
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs12
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs12
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx800.rs11
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs46
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs41
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs41
-rw-r--r--compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs20
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs13
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs33
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs37
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs34
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs12
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx800.rs11
-rw-r--r--compiler/rustc_trait_selection/messages.ftl3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs284
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs16
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs26
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs10
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs14
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs28
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs194
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs12
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs20
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs20
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_normalize.rs73
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs209
-rw-r--r--compiler/rustc_traits/src/type_op.rs8
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs1
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs4
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs69
-rw-r--r--compiler/rustc_type_ir/src/ty_kind/closure.rs20
-rw-r--r--compiler/rustc_type_ir/src/visit.rs8
428 files changed, 5835 insertions, 4104 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 8e73df63ef5..ad942e9b494 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -28,6 +28,7 @@ use rustc_data_structures::packed::Pu128;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::tagged_ptr::Tag;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 pub use rustc_span::AttrId;
 use rustc_span::source_map::{Spanned, respan};
@@ -99,7 +100,7 @@ pub struct Path {
 impl PartialEq<Symbol> for Path {
     #[inline]
     fn eq(&self, symbol: &Symbol) -> bool {
-        self.segments.len() == 1 && { self.segments[0].ident.name == *symbol }
+        matches!(&self.segments[..], [segment] if segment.ident.name == *symbol)
     }
 }
 
@@ -120,13 +121,13 @@ impl Path {
     }
 
     pub fn is_global(&self) -> bool {
-        !self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot
+        self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot)
     }
 
     /// If this path is a single identifier with no arguments, does not ensure
     /// that the path resolves to a const param, the caller should check this.
     pub fn is_potential_trivial_const_arg(&self) -> bool {
-        self.segments.len() == 1 && self.segments[0].args.is_none()
+        matches!(self.segments[..], [PathSegment { args: None, .. }])
     }
 }
 
@@ -287,6 +288,7 @@ impl ParenthesizedArgs {
     }
 }
 
+use crate::AstDeref;
 pub use crate::node_id::{CRATE_NODE_ID, DUMMY_NODE_ID, NodeId};
 
 /// Modifiers on a trait bound like `~const`, `?` and `!`.
@@ -2165,6 +2167,14 @@ impl Ty {
         }
         final_ty
     }
+
+    pub fn is_maybe_parenthesised_infer(&self) -> bool {
+        match &self.kind {
+            TyKind::Infer => true,
+            TyKind::Paren(inner) => inner.ast_deref().is_maybe_parenthesised_infer(),
+            _ => false,
+        }
+    }
 }
 
 #[derive(Clone, Encodable, Decodable, Debug)]
@@ -2269,10 +2279,32 @@ impl TyKind {
 
 /// Syntax used to declare a trait object.
 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+#[repr(u8)]
 pub enum TraitObjectSyntax {
-    Dyn,
-    DynStar,
-    None,
+    // SAFETY: When adding new variants make sure to update the `Tag` impl.
+    Dyn = 0,
+    DynStar = 1,
+    None = 2,
+}
+
+/// SAFETY: `TraitObjectSyntax` only has 3 data-less variants which means
+/// it can be represented with a `u2`. We use `repr(u8)` to guarantee the
+/// discriminants of the variants are no greater than `3`.
+unsafe impl Tag for TraitObjectSyntax {
+    const BITS: u32 = 2;
+
+    fn into_usize(self) -> usize {
+        self as u8 as usize
+    }
+
+    unsafe fn from_usize(tag: usize) -> Self {
+        match tag {
+            0 => TraitObjectSyntax::Dyn,
+            1 => TraitObjectSyntax::DynStar,
+            2 => TraitObjectSyntax::None,
+            _ => unreachable!(),
+        }
+    }
 }
 
 #[derive(Clone, Encodable, Decodable, Debug)]
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 51f18580013..df2f4b88712 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -302,7 +302,7 @@ impl AttrItem {
 impl MetaItem {
     /// For a single-segment meta item, returns its name; otherwise, returns `None`.
     pub fn ident(&self) -> Option<Ident> {
-        if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
+        if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
     }
 
     pub fn name_or_empty(&self) -> Symbol {
diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs
index ab1413d6080..12cbb3b2a15 100644
--- a/compiler/rustc_ast/src/entry.rs
+++ b/compiler/rustc_ast/src/entry.rs
@@ -18,12 +18,6 @@ pub enum EntryPointType {
     /// fn main() {}
     /// ```
     RustcMainAttr,
-    /// This is a function with the `#[start]` attribute.
-    /// ```ignore (clashes with test entrypoint)
-    /// #[start]
-    /// fn main() {}
-    /// ```
-    Start,
     /// This function is **not** an entrypoint but simply named `main` (not at the root).
     /// This is only used for diagnostics.
     /// ```
@@ -40,9 +34,7 @@ pub fn entry_point_type(
     at_root: bool,
     name: Option<Symbol>,
 ) -> EntryPointType {
-    if attr::contains_name(attrs, sym::start) {
-        EntryPointType::Start
-    } else if attr::contains_name(attrs, sym::rustc_main) {
+    if attr::contains_name(attrs, sym::rustc_main) {
         EntryPointType::RustcMainAttr
     } else if let Some(name) = name
         && name == sym::main
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index aa88e8369d5..3459d39131a 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1813,10 +1813,10 @@ pub fn walk_flat_map_stmt<T: MutVisitor>(
         .into_iter()
         .map(|kind| Stmt { id, kind, span })
         .collect();
-    match stmts.len() {
-        0 => {}
-        1 => vis.visit_span(&mut stmts[0].span),
-        2.. => panic!(
+    match &mut stmts[..] {
+        [] => {}
+        [stmt] => vis.visit_span(&mut stmt.span),
+        _ => panic!(
             "cloning statement `NodeId`s is prohibited by default, \
              the visitor should implement custom statement visiting"
         ),
diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs
index f39142f08ba..e12818623d8 100644
--- a/compiler/rustc_ast/src/util/comments.rs
+++ b/compiler/rustc_ast/src/util/comments.rs
@@ -39,7 +39,7 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
         let mut i = 0;
         let mut j = lines.len();
         // first line of all-stars should be omitted
-        if !lines.is_empty() && lines[0].chars().all(|c| c == '*') {
+        if lines.first().is_some_and(|line| line.chars().all(|c| c == '*')) {
             i += 1;
         }
 
@@ -97,7 +97,7 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
                 return None;
             }
         }
-        if lines.is_empty() { None } else { Some(lines[0][..i].into()) }
+        Some(lines.first()?[..i].to_string())
     }
 
     let data_s = data.as_str();
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 266e77c0e02..f9fe4938ca8 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -72,7 +72,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         if let Some(local_sig_id) = def_id.as_local() {
             // The value may be missing due to recursive delegation.
             // Error will be emitted later during HIR ty lowering.
-            self.resolver.delegation_fn_sigs.get(&local_sig_id).map_or(false, |sig| sig.has_self)
+            self.resolver.delegation_fn_sigs.get(&local_sig_id).is_some_and(|sig| sig.has_self)
         } else {
             match self.tcx.def_kind(def_id) {
                 DefKind::Fn => false,
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index a76ca6772e5..f31e2c65c79 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -2159,7 +2159,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let path = hir::ExprKind::Path(hir::QPath::TypeRelative(
             self.arena.alloc(self.ty(span, hir::TyKind::Path(qpath))),
             self.arena.alloc(hir::PathSegment::new(
-                Ident::new(name, span),
+                Ident::new(name, self.lower_span(span)),
                 self.next_id(),
                 Res::Err,
             )),
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 29d4fb9ef25..f8fb21d5cd0 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -1,3 +1,4 @@
+use intravisit::InferKind;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
@@ -78,24 +79,31 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
 
         // Make sure that the DepNode of some node coincides with the HirId
         // owner of that node.
-        if cfg!(debug_assertions) && hir_id.owner != self.owner {
-            span_bug!(
-                span,
-                "inconsistent HirId at `{:?}` for `{:?}`: \
+        if cfg!(debug_assertions) {
+            if hir_id.owner != self.owner {
+                span_bug!(
+                    span,
+                    "inconsistent HirId at `{:?}` for `{node:?}`: \
                      current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
-                self.tcx.sess.source_map().span_to_diagnostic_string(span),
-                node,
-                self.tcx
-                    .definitions_untracked()
-                    .def_path(self.owner.def_id)
-                    .to_string_no_crate_verbose(),
-                self.owner,
-                self.tcx
-                    .definitions_untracked()
-                    .def_path(hir_id.owner.def_id)
-                    .to_string_no_crate_verbose(),
-                hir_id.owner,
-            )
+                    self.tcx.sess.source_map().span_to_diagnostic_string(span),
+                    self.tcx
+                        .definitions_untracked()
+                        .def_path(self.owner.def_id)
+                        .to_string_no_crate_verbose(),
+                    self.owner,
+                    self.tcx
+                        .definitions_untracked()
+                        .def_path(hir_id.owner.def_id)
+                        .to_string_no_crate_verbose(),
+                    hir_id.owner,
+                )
+            }
+            if self.tcx.sess.opts.incremental.is_some()
+                && span.parent().is_none()
+                && !span.is_dummy()
+            {
+                span_bug!(span, "span without a parent: {:#?}, {node:?}", span.data())
+            }
         }
 
         self.nodes[hir_id.local_id] = ParentedNode { parent: self.parent_node, node };
@@ -258,14 +266,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         });
     }
 
-    fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir>) {
-        self.insert(const_arg.span(), const_arg.hir_id, Node::ConstArg(const_arg));
-
-        self.with_parent(const_arg.hir_id, |this| {
-            intravisit::walk_const_arg(this, const_arg);
-        });
-    }
-
     fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
         self.insert(expr.span, expr.hir_id, Node::Expr(expr));
 
@@ -295,22 +295,41 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         intravisit::walk_path_segment(self, path_segment);
     }
 
-    fn visit_ty(&mut self, ty: &'hir Ty<'hir>) {
-        self.insert(ty.span, ty.hir_id, Node::Ty(ty));
+    fn visit_ty(&mut self, ty: &'hir Ty<'hir, AmbigArg>) {
+        self.insert(ty.span, ty.hir_id, Node::Ty(ty.as_unambig_ty()));
 
         self.with_parent(ty.hir_id, |this| {
             intravisit::walk_ty(this, ty);
         });
     }
 
-    fn visit_infer(&mut self, inf: &'hir InferArg) {
-        self.insert(inf.span, inf.hir_id, Node::Infer(inf));
+    fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir, AmbigArg>) {
+        self.insert(
+            const_arg.as_unambig_ct().span(),
+            const_arg.hir_id,
+            Node::ConstArg(const_arg.as_unambig_ct()),
+        );
 
-        self.with_parent(inf.hir_id, |this| {
-            intravisit::walk_inf(this, inf);
+        self.with_parent(const_arg.hir_id, |this| {
+            intravisit::walk_ambig_const_arg(this, const_arg);
         });
     }
 
+    fn visit_infer(
+        &mut self,
+        inf_id: HirId,
+        inf_span: Span,
+        kind: InferKind<'hir>,
+    ) -> Self::Result {
+        match kind {
+            InferKind::Ty(ty) => self.insert(inf_span, inf_id, Node::Ty(ty)),
+            InferKind::Const(ct) => self.insert(inf_span, inf_id, Node::ConstArg(ct)),
+            InferKind::Ambig(inf) => self.insert(inf_span, inf_id, Node::Infer(inf)),
+        }
+
+        self.visit_id(inf_id);
+    }
+
     fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) {
         self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr));
 
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 61d7da429f8..74870d74150 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1092,6 +1092,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             // this as a special case.
             return self.lower_fn_body(decl, |this| {
                 if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic) {
+                    let span = this.lower_span(span);
                     let empty_block = hir::Block {
                         hir_id: this.next_id(),
                         stmts: &[],
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 0e28590bd66..b9f1a4220b8 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -48,6 +48,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::tagged_ptr::TaggedRef;
 use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
 use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
@@ -1083,17 +1084,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         match arg {
             ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)),
             ast::GenericArg::Type(ty) => {
+                // We cannot just match on `TyKind::Infer` as `(_)` is represented as
+                // `TyKind::Paren(TyKind::Infer)` and should also be lowered to `GenericArg::Infer`
+                if ty.is_maybe_parenthesised_infer() {
+                    return GenericArg::Infer(hir::InferArg {
+                        hir_id: self.lower_node_id(ty.id),
+                        span: self.lower_span(ty.span),
+                    });
+                }
+
                 match &ty.kind {
-                    TyKind::Infer if self.tcx.features().generic_arg_infer() => {
-                        return GenericArg::Infer(hir::InferArg {
-                            hir_id: self.lower_node_id(ty.id),
-                            span: self.lower_span(ty.span),
-                        });
-                    }
                     // We parse const arguments as path types as we cannot distinguish them during
                     // parsing. We try to resolve that ambiguity by attempting resolution in both the
                     // type and value namespaces. If we resolved the path in the value namespace, we
                     // transform it into a generic const argument.
+                    //
+                    // FIXME: Should we be handling `(PATH_TO_CONST)`?
                     TyKind::Path(None, path) => {
                         if let Some(res) = self
                             .resolver
@@ -1110,15 +1116,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                                 let ct =
                                     self.lower_const_path_to_const_arg(path, res, ty.id, ty.span);
-                                return GenericArg::Const(ct);
+                                return GenericArg::Const(ct.try_as_ambig_ct().unwrap());
                             }
                         }
                     }
                     _ => {}
                 }
-                GenericArg::Type(self.lower_ty(ty, itctx))
+                GenericArg::Type(self.lower_ty(ty, itctx).try_as_ambig_ty().unwrap())
+            }
+            ast::GenericArg::Const(ct) => {
+                GenericArg::Const(self.lower_anon_const_to_const_arg(ct).try_as_ambig_ct().unwrap())
             }
-            ast::GenericArg::Const(ct) => GenericArg::Const(self.lower_anon_const_to_const_arg(ct)),
         }
     }
 
@@ -1158,7 +1166,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let lifetime_bound = this.elided_dyn_bound(t.span);
                 (bounds, lifetime_bound)
             });
-            let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
+            let kind = hir::TyKind::TraitObject(
+                bounds,
+                TaggedRef::new(lifetime_bound, TraitObjectSyntax::None),
+            );
             return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
         }
 
@@ -1185,7 +1196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
     fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
         let kind = match &t.kind {
-            TyKind::Infer => hir::TyKind::Infer,
+            TyKind::Infer => hir::TyKind::Infer(()),
             TyKind::Err(guar) => hir::TyKind::Err(*guar),
             TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
             TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
@@ -1309,7 +1320,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
                     (bounds, lifetime_bound)
                 });
-                hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
+                hir::TyKind::TraitObject(bounds, TaggedRef::new(lifetime_bound, *kind))
             }
             TyKind::ImplTrait(def_node_id, bounds) => {
                 let span = t.span;
@@ -2041,7 +2052,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     )
                     .stash(c.value.span, StashKey::UnderscoreForArrayLengths);
                 }
-                let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span));
+                let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ());
                 self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind })
             }
             _ => self.lower_anon_const_to_const_arg(c),
@@ -2365,8 +2376,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         hir_id = self.next_id();
                         hir::TyKind::TraitObject(
                             arena_vec![self; principal],
-                            self.elided_dyn_bound(span),
-                            TraitObjectSyntax::None,
+                            TaggedRef::new(self.elided_dyn_bound(span), TraitObjectSyntax::None),
                         )
                     }
                     _ => hir::TyKind::Path(hir::QPath::Resolved(None, path)),
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index abd314ae74c..3c78ed0497d 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -375,24 +375,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         expr: &Expr,
         allow_paths: bool,
     ) -> &'hir hir::PatExpr<'hir> {
+        let span = self.lower_span(expr.span);
         let err = |guar| hir::PatExprKind::Lit {
-            lit: self.arena.alloc(respan(self.lower_span(expr.span), LitKind::Err(guar))),
+            lit: self.arena.alloc(respan(span, LitKind::Err(guar))),
             negated: false,
         };
         let kind = match &expr.kind {
             ExprKind::Lit(lit) => {
-                hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: false }
+                hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false }
             }
             ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)),
             ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit {
-                lit: self.arena.alloc(respan(
-                    self.lower_span(expr.span),
-                    LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked),
-                )),
+                lit: self
+                    .arena
+                    .alloc(respan(span, LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked))),
                 negated: false,
             },
             ExprKind::Err(guar) => err(*guar),
-            ExprKind::Dummy => span_bug!(expr.span, "lowered ExprKind::Dummy"),
+            ExprKind::Dummy => span_bug!(span, "lowered ExprKind::Dummy"),
             ExprKind::Path(qself, path) if allow_paths => hir::PatExprKind::Path(self.lower_qpath(
                 expr.id,
                 qself,
@@ -403,21 +403,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 None,
             )),
             ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => {
-                hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: true }
+                hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: true }
             }
             _ => {
                 let pattern_from_macro = expr.is_approximately_pattern();
                 let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
-                    span: expr.span,
+                    span,
                     pattern_from_macro_note: pattern_from_macro,
                 });
                 err(guar)
             }
         };
-        self.arena.alloc(hir::PatExpr {
-            hir_id: self.lower_node_id(expr.id),
-            span: expr.span,
-            kind,
-        })
+        self.arena.alloc(hir::PatExpr { hir_id: self.lower_node_id(expr.id), span, kind })
     }
 }
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 043144a5464..75abff7461b 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -525,7 +525,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
             FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
         };
-        let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
+        let args = smallvec![GenericArg::Type(
+            self.arena.alloc(self.ty_tup(*inputs_span, inputs)).try_as_ambig_ty().unwrap()
+        )];
 
         // If we have a bound like `async Fn() -> T`, make sure that we mark the
         // `Output = T` associated type bound with the right feature gates.
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 94746212138..80b99f94485 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -83,7 +83,7 @@ impl<'a> PostExpansionVisitor<'a> {
                 feature_err_issue(&self.sess, feature, span, GateIssue::Language, explain).emit();
             }
             Err(abi::AbiDisabled::Unrecognized) => {
-                if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) {
+                if self.sess.opts.pretty.is_none_or(|ppm| ppm.needs_hir()) {
                     self.sess.dcx().span_delayed_bug(
                         span,
                         format!(
@@ -230,18 +230,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 }
             }
 
-            ast::ItemKind::Fn(..) => {
-                if attr::contains_name(&i.attrs, sym::start) {
-                    gate!(
-                        &self,
-                        start,
-                        i.span,
-                        "`#[start]` functions are experimental and their signature may change \
-                         over time"
-                    );
-                }
-            }
-
             ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => {
                 for attr in attr::filter_by_name(&i.attrs, sym::repr) {
                     for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) {
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index def6b16ee8a..b4027a096c5 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -35,13 +35,25 @@ pub enum InstructionSetAttr {
     ArmT32,
 }
 
-#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic, Default)]
 pub enum OptimizeAttr {
-    None,
+    /// No `#[optimize(..)]` attribute
+    #[default]
+    Default,
+    /// `#[optimize(none)]`
+    DoNotOptimize,
+    /// `#[optimize(speed)]`
     Speed,
+    /// `#[optimize(size)]`
     Size,
 }
 
+impl OptimizeAttr {
+    pub fn do_not_optimize(&self) -> bool {
+        matches!(self, Self::DoNotOptimize)
+    }
+}
+
 #[derive(Clone, Debug, Encodable, Decodable)]
 pub enum DiagnosticAttribute {
     // tidy-alphabetical-start
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 124f0aa3eff..28c381160b8 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -166,7 +166,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &impl AttributeExt) -> Vec<ReprAttr
                 // the `check_mod_attrs` pass, but this pass doesn't always run
                 // (e.g. if we only pretty-print the source), so we have to gate
                 // the `span_delayed_bug` call as follows:
-                if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
+                if sess.opts.pretty.is_none_or(|pp| pp.needs_analysis()) {
                     dcx.span_delayed_bug(item.span(), "unrecognized representation hint");
                 }
             }
diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl
index ada20e5c614..c00e6dde919 100644
--- a/compiler/rustc_borrowck/messages.ftl
+++ b/compiler/rustc_borrowck/messages.ftl
@@ -92,6 +92,9 @@ borrowck_lifetime_constraints_error =
 borrowck_limitations_implies_static =
     due to current limitations in the borrow checker, this implies a `'static` lifetime
 
+borrowck_long_type_consider_verbose = consider using `--verbose` to print the full type name to the console
+borrowck_long_type_full_path = the full type name has been written to '{$path}'
+
 borrowck_move_closure_suggestion =
     consider adding 'move' keyword before the nested closure
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index da59f9f9ebd..07dcbba019a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -39,7 +39,9 @@ use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
 use rustc_trait_selection::error_reporting::traits::call_kind::CallKind;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
+use rustc_trait_selection::traits::{
+    Obligation, ObligationCause, ObligationCtxt, supertrait_def_ids,
+};
 use tracing::{debug, instrument};
 
 use super::explain_borrow::{BorrowExplanation, LaterUseKind};
@@ -287,6 +289,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 None => "value".to_owned(),
             };
             if needs_note {
+                let mut path = None;
+                let ty = self.infcx.tcx.short_ty_string(ty, &mut path);
                 if let Some(local) = place.as_local() {
                     let span = self.body.local_decls[local].source_info.span;
                     err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
@@ -302,6 +306,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         place: &note_msg,
                     });
                 };
+                if let Some(path) = path {
+                    err.subdiagnostic(crate::session_diagnostics::LongTypePath {
+                        path: path.display().to_string(),
+                    });
+                }
             }
 
             if let UseSpans::FnSelfUse {
@@ -658,8 +667,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             clause.as_trait_clause().is_some_and(|tc| {
                 tc.self_ty().skip_binder().is_param(param.index)
                     && tc.polarity() == ty::PredicatePolarity::Positive
-                    && tcx
-                        .supertrait_def_ids(tc.def_id())
+                    && supertrait_def_ids(tcx, tc.def_id())
                         .flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())
                         .any(|item| item.fn_has_self_parameter)
             })
@@ -2480,7 +2488,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                     // To support cases like `|| { v.call(|this| v.get()) }`
                     // FIXME: actually support such cases (need to figure out how to move from the
                     // capture place to original local).
-                    && self.res.as_ref().map_or(true, |(prev_res, _)| prev_res.span.contains(ex.span))
+                    && self.res.as_ref().is_none_or(|(prev_res, _)| prev_res.span.contains(ex.span))
                 {
                     self.res = Some((ex, closure));
                 }
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 5c0c1d0eb86..2656e0bb6a4 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -131,10 +131,10 @@ impl<'tcx> BorrowExplanation<'tcx> {
                     && let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
                 {
                     suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err);
-                } else if path_span.map_or(true, |path_span| path_span == var_or_use_span) {
+                } else if path_span.is_none_or(|path_span| path_span == var_or_use_span) {
                     // We can use `var_or_use_span` if either `path_span` is not present, or both
                     // spans are the same.
-                    if borrow_span.map_or(true, |sp| !sp.overlaps(var_or_use_span)) {
+                    if borrow_span.is_none_or(|sp| !sp.overlaps(var_or_use_span)) {
                         err.span_label(
                             var_or_use_span,
                             format!("{borrow_desc}borrow later {message}"),
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index beacbdbd3fa..14a900f38e9 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -596,12 +596,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         self.suggest_cloning(err, place_ty, expr, None);
                     }
 
+                    let mut path = None;
+                    let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path);
                     err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
                         is_partial_move: false,
-                        ty: place_ty,
+                        ty,
                         place: &place_desc,
                         span,
                     });
+                    if let Some(path) = path {
+                        err.subdiagnostic(crate::session_diagnostics::LongTypePath {
+                            path: path.display().to_string(),
+                        });
+                    }
                 } else {
                     binds_to.sort();
                     binds_to.dedup();
@@ -628,12 +635,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                     self.suggest_cloning(err, place_ty, expr, Some(use_spans));
                 }
 
+                let mut path = None;
+                let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path);
                 err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
                     is_partial_move: false,
-                    ty: place_ty,
+                    ty,
                     place: &place_desc,
                     span: use_span,
                 });
+                if let Some(path) = path {
+                    err.subdiagnostic(crate::session_diagnostics::LongTypePath {
+                        path: path.display().to_string(),
+                    });
+                }
 
                 use_spans.args_subdiag(err, |args_span| {
                     crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
@@ -831,12 +845,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                     self.suggest_cloning(err, bind_to.ty, expr, None);
                 }
 
+                let mut path = None;
+                let ty = self.infcx.tcx.short_ty_string(bind_to.ty, &mut path);
                 err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
                     is_partial_move: false,
-                    ty: bind_to.ty,
+                    ty,
                     place: place_desc,
                     span: binding_span,
                 });
+                if let Some(path) = path {
+                    err.subdiagnostic(crate::session_diagnostics::LongTypePath {
+                        path: path.display().to_string(),
+                    });
+                }
             }
         }
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index f0baa20648c..3c4e4c29197 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -8,7 +8,7 @@ use rustc_hir::QPath::Resolved;
 use rustc_hir::WherePredicateKind::BoundPredicate;
 use rustc_hir::def::Res::Def;
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::Visitor;
+use rustc_hir::intravisit::VisitorExt;
 use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
 use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
 use rustc_middle::bug;
@@ -887,7 +887,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 if alias_ty.span.desugaring_kind().is_some() {
                     // Skip `async` desugaring `impl Future`.
                 }
-                if let TyKind::TraitObject(_, lt, _) = alias_ty.kind {
+                if let TyKind::TraitObject(_, lt) = alias_ty.kind {
                     if lt.ident.name == kw::Empty {
                         spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
                     } else {
@@ -987,7 +987,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         for found_did in found_dids {
             let mut traits = vec![];
             let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
-            hir_v.visit_ty(self_ty);
+            hir_v.visit_ty_unambig(self_ty);
             debug!("trait spans found: {:?}", traits);
             for span in &traits {
                 let mut multi_span: MultiSpan = vec![*span].into();
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 9349b46ec5b..ccd13badad7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -432,7 +432,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
             // must highlight the variable.
             // NOTE(eddyb) this is handled in/by the sole caller
             // (`give_name_if_anonymous_region_appears_in_arguments`).
-            hir::TyKind::Infer => None,
+            hir::TyKind::Infer(()) => None,
 
             _ => Some(argument_hir_ty),
         }
@@ -615,7 +615,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
                 }
 
                 (GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => {
-                    search_stack.push((ty, hir_ty));
+                    search_stack.push((ty, hir_ty.as_unambig_ty()));
                 }
 
                 (GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => {
diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs
index a6d80149034..40e801d0388 100644
--- a/compiler/rustc_borrowck/src/polonius/dump.rs
+++ b/compiler/rustc_borrowck/src/polonius/dump.rs
@@ -1,7 +1,9 @@
 use std::io;
 
-use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options};
-use rustc_middle::mir::{Body, ClosureRegionRequirements, PassWhere};
+use rustc_middle::mir::pretty::{
+    PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer,
+};
+use rustc_middle::mir::{Body, ClosureRegionRequirements};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::MirIncludeSpans;
 
@@ -10,9 +12,6 @@ use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSe
 use crate::{BorrowckInferCtxt, RegionInferenceContext};
 
 /// `-Zdump-mir=polonius` dumps MIR annotated with NLL and polonius specific information.
-// Note: this currently duplicates most of NLL MIR, with some additions for the localized outlives
-// constraints. This is ok for now as this dump will change in the near future to an HTML file to
-// become more useful.
 pub(crate) fn dump_polonius_mir<'tcx>(
     infcx: &BorrowckInferCtxt<'tcx>,
     body: &Body<'tcx>,
@@ -26,12 +25,100 @@ pub(crate) fn dump_polonius_mir<'tcx>(
         return;
     }
 
+    if !dump_enabled(tcx, "polonius", body.source.def_id()) {
+        return;
+    }
+
     let localized_outlives_constraints = localized_outlives_constraints
         .expect("missing localized constraints with `-Zpolonius=next`");
 
-    // We want the NLL extra comments printed by default in NLL MIR dumps (they were removed in
-    // #112346). Specifying `-Z mir-include-spans` on the CLI still has priority: for example,
-    // they're always disabled in mir-opt tests to make working with blessed dumps easier.
+    let _: io::Result<()> = try {
+        let mut file = create_dump_file(tcx, "html", false, "polonius", &0, body)?;
+        emit_polonius_dump(
+            tcx,
+            body,
+            regioncx,
+            borrow_set,
+            localized_outlives_constraints,
+            closure_region_requirements,
+            &mut file,
+        )?;
+    };
+}
+
+/// The polonius dump consists of:
+/// - the NLL MIR
+/// - the list of polonius localized constraints
+/// - a mermaid graph of the CFG
+fn emit_polonius_dump<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
+    regioncx: &RegionInferenceContext<'tcx>,
+    borrow_set: &BorrowSet<'tcx>,
+    localized_outlives_constraints: LocalizedOutlivesConstraintSet,
+    closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
+    out: &mut dyn io::Write,
+) -> io::Result<()> {
+    // Prepare the HTML dump file prologue.
+    writeln!(out, "<!DOCTYPE html>")?;
+    writeln!(out, "<html>")?;
+    writeln!(out, "<head><title>Polonius MIR dump</title></head>")?;
+    writeln!(out, "<body>")?;
+
+    // Section 1: the NLL + Polonius MIR.
+    writeln!(out, "<div>")?;
+    writeln!(out, "Raw MIR dump")?;
+    writeln!(out, "<code><pre>")?;
+    emit_html_mir(
+        tcx,
+        body,
+        regioncx,
+        borrow_set,
+        localized_outlives_constraints,
+        closure_region_requirements,
+        out,
+    )?;
+    writeln!(out, "</pre></code>")?;
+    writeln!(out, "</div>")?;
+
+    // Section 2: mermaid visualization of the CFG.
+    writeln!(out, "<div>")?;
+    writeln!(out, "Control-flow graph")?;
+    writeln!(out, "<code><pre class='mermaid'>")?;
+    emit_mermaid_cfg(body, out)?;
+    writeln!(out, "</pre></code>")?;
+    writeln!(out, "</div>")?;
+
+    // Finalize the dump with the HTML epilogue.
+    writeln!(
+        out,
+        "<script src='https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js'></script>"
+    )?;
+    writeln!(out, "<script>")?;
+    writeln!(out, "mermaid.initialize({{ startOnLoad: false, maxEdges: 100 }});")?;
+    writeln!(out, "mermaid.run({{ querySelector: '.mermaid' }})")?;
+    writeln!(out, "</script>")?;
+    writeln!(out, "</body>")?;
+    writeln!(out, "</html>")?;
+
+    Ok(())
+}
+
+/// Emits the polonius MIR, as escaped HTML.
+fn emit_html_mir<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
+    regioncx: &RegionInferenceContext<'tcx>,
+    borrow_set: &BorrowSet<'tcx>,
+    localized_outlives_constraints: LocalizedOutlivesConstraintSet,
+    closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
+    out: &mut dyn io::Write,
+) -> io::Result<()> {
+    // Buffer the regular MIR dump to be able to escape it.
+    let mut buffer = Vec::new();
+
+    // We want the NLL extra comments printed by default in NLL MIR dumps. Specifying `-Z
+    // mir-include-spans` on the CLI still has priority.
     let options = PrettyPrintMirOptions {
         include_extra_comments: matches!(
             tcx.sess.opts.unstable_opts.mir_include_spans,
@@ -39,12 +126,12 @@ pub(crate) fn dump_polonius_mir<'tcx>(
         ),
     };
 
-    dump_mir_with_options(
+    dump_mir_to_writer(
         tcx,
-        false,
         "polonius",
         &0,
         body,
+        &mut buffer,
         |pass_where, out| {
             emit_polonius_mir(
                 tcx,
@@ -57,7 +144,27 @@ pub(crate) fn dump_polonius_mir<'tcx>(
             )
         },
         options,
-    );
+    )?;
+
+    // Escape the handful of characters that need it. We don't need to be particularly efficient:
+    // we're actually writing into a buffered writer already. Note that MIR dumps are valid UTF-8.
+    let buffer = String::from_utf8_lossy(&buffer);
+    for ch in buffer.chars() {
+        let escaped = match ch {
+            '>' => "&gt;",
+            '<' => "&lt;",
+            '&' => "&amp;",
+            '\'' => "&#39;",
+            '"' => "&quot;",
+            _ => {
+                // The common case, no escaping needed.
+                write!(out, "{}", ch)?;
+                continue;
+            }
+        };
+        write!(out, "{}", escaped)?;
+    }
+    Ok(())
 }
 
 /// Produces the actual NLL + Polonius MIR sections to emit during the dumping process.
@@ -102,3 +209,55 @@ fn emit_polonius_mir<'tcx>(
 
     Ok(())
 }
+
+/// Emits a mermaid flowchart of the CFG blocks and edges, similar to the graphviz version.
+fn emit_mermaid_cfg(body: &Body<'_>, out: &mut dyn io::Write) -> io::Result<()> {
+    use rustc_middle::mir::{TerminatorEdges, TerminatorKind};
+
+    // The mermaid chart type: a top-down flowchart.
+    writeln!(out, "flowchart TD")?;
+
+    // Emit the block nodes.
+    for (block_idx, block) in body.basic_blocks.iter_enumerated() {
+        let block_idx = block_idx.as_usize();
+        let cleanup = if block.is_cleanup { " (cleanup)" } else { "" };
+        writeln!(out, "{block_idx}[\"bb{block_idx}{cleanup}\"]")?;
+    }
+
+    // Emit the edges between blocks, from the terminator edges.
+    for (block_idx, block) in body.basic_blocks.iter_enumerated() {
+        let block_idx = block_idx.as_usize();
+        let terminator = block.terminator();
+        match terminator.edges() {
+            TerminatorEdges::None => {}
+            TerminatorEdges::Single(bb) => {
+                writeln!(out, "{block_idx} --> {}", bb.as_usize())?;
+            }
+            TerminatorEdges::Double(bb1, bb2) => {
+                if matches!(terminator.kind, TerminatorKind::FalseEdge { .. }) {
+                    writeln!(out, "{block_idx} --> {}", bb1.as_usize())?;
+                    writeln!(out, "{block_idx} -- imaginary --> {}", bb2.as_usize())?;
+                } else {
+                    writeln!(out, "{block_idx} --> {}", bb1.as_usize())?;
+                    writeln!(out, "{block_idx} -- unwind --> {}", bb2.as_usize())?;
+                }
+            }
+            TerminatorEdges::AssignOnReturn { return_, cleanup, .. } => {
+                for to_idx in return_ {
+                    writeln!(out, "{block_idx} --> {}", to_idx.as_usize())?;
+                }
+
+                if let Some(to_idx) = cleanup {
+                    writeln!(out, "{block_idx} -- unwind --> {}", to_idx.as_usize())?;
+                }
+            }
+            TerminatorEdges::SwitchInt { targets, .. } => {
+                for to_idx in targets.all_targets() {
+                    writeln!(out, "{block_idx} --> {}", to_idx.as_usize())?;
+                }
+            }
+        }
+    }
+
+    Ok(())
+}
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index 4be5d0dbf42..2c37d2bc123 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -459,17 +459,24 @@ pub(crate) enum OnClosureNote<'a> {
 }
 
 #[derive(Subdiagnostic)]
-pub(crate) enum TypeNoCopy<'a, 'tcx> {
+#[note(borrowck_long_type_full_path)]
+#[note(borrowck_long_type_consider_verbose)]
+pub(crate) struct LongTypePath {
+    pub(crate) path: String,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum TypeNoCopy<'a> {
     #[label(borrowck_ty_no_impl_copy)]
     Label {
         is_partial_move: bool,
-        ty: Ty<'tcx>,
+        ty: String,
         place: &'a str,
         #[primary_span]
         span: Span,
     },
     #[note(borrowck_ty_no_impl_copy)]
-    Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str },
+    Note { is_partial_move: bool, ty: String, place: &'a str },
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 3903c45fda5..bffd9f38334 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -185,7 +185,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 CustomTypeOp::new(
                     |ocx| {
                         let structurally_normalize = |ty| {
-                            ocx.structurally_normalize(
+                            ocx.structurally_normalize_ty(
                                 &ObligationCause::misc(
                                     location.to_locations().span(body),
                                     body.source.def_id().expect_local(),
@@ -230,7 +230,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 ConstraintCategory::Boring,
                 CustomTypeOp::new(
                     |ocx| {
-                        ocx.structurally_normalize(
+                        ocx.structurally_normalize_ty(
                             &ObligationCause::misc(
                                 location.to_locations().span(body),
                                 body.source.def_id().expect_local(),
diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
index 49706db0e0b..82417a86dd9 100644
--- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
@@ -157,7 +157,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
         {
             cx.dcx().emit_err(RequiresMaybeSized {
                 span: pointee_ty_ident.span,
-                name: pointee_ty_ident.name.to_ident_string(),
+                name: pointee_ty_ident,
             });
             return;
         }
@@ -471,5 +471,5 @@ struct TooManyPointees {
 struct RequiresMaybeSized {
     #[primary_span]
     span: Span,
-    name: String,
+    name: Ident,
 }
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 6071d36f8eb..0918403b855 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -16,6 +16,7 @@
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_quote)]
 #![feature(rustdoc_internals)]
+#![feature(string_from_utf8_lossy_owned)]
 #![feature(try_blocks)]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 123b96f6bca..d163da3ddea 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -13,7 +13,7 @@ use rustc_expand::base::{
 use rustc_expand::module::DirOwnership;
 use rustc_lint_defs::BuiltinLintDiag;
 use rustc_parse::parser::{ForceCollect, Parser};
-use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal};
+use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error};
 use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{Pos, Span, Symbol};
@@ -209,9 +209,10 @@ pub(crate) fn expand_include_str(
                 let interned_src = Symbol::intern(src);
                 MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src))
             }
-            Err(_) => {
-                let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file"));
-                DummyResult::any(sp, guar)
+            Err(utf8err) => {
+                let mut err = cx.dcx().struct_span_err(sp, format!("`{path}` wasn't a utf-8 file"));
+                utf8_error(cx.source_map(), path.as_str(), None, &mut err, utf8err, &bytes[..]);
+                DummyResult::any(sp, err.emit())
             }
         },
         Err(dummy) => dummy,
@@ -273,7 +274,7 @@ fn load_binary_file(
                     .and_then(|path| path.into_os_string().into_string().ok());
 
                 if let Some(new_path) = new_path {
-                    err.span_suggestion(
+                    err.span_suggestion_verbose(
                         path_span,
                         "there is a file with the same name in a different directory",
                         format!("\"{}\"", new_path.replace('\\', "/").escape_debug()),
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 46446598943..31b068bd33d 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -204,11 +204,11 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
         ast::mut_visit::walk_item(self, item);
         self.depth -= 1;
 
-        // Remove any #[rustc_main] or #[start] from the AST so it doesn't
+        // Remove any #[rustc_main] from the AST so it doesn't
         // clash with the one we're going to add, but mark it as
         // #[allow(dead_code)] to avoid printing warnings.
         match entry_point_type(&item, self.depth == 0) {
-            EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
+            EntryPointType::MainNamed | EntryPointType::RustcMainAttr => {
                 let allow_dead_code = attr::mk_attr_nested_word(
                     &self.sess.psess.attr_id_generator,
                     ast::AttrStyle::Outer,
@@ -217,8 +217,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
                     sym::dead_code,
                     self.def_site,
                 );
-                item.attrs
-                    .retain(|attr| !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start));
+                item.attrs.retain(|attr| !attr.has_name(sym::rustc_main));
                 item.attrs.push(allow_dead_code);
             }
             EntryPointType::None | EntryPointType::OtherMain => {}
diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs
index 8de419a0c4e..bcb2b4881eb 100644
--- a/compiler/rustc_codegen_cranelift/build_system/tests.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs
@@ -151,7 +151,7 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
         apply_patches(
             &runner.dirs,
             "coretests",
-            &runner.stdlib_source.join("library/core/tests"),
+            &runner.stdlib_source.join("library/coretests"),
             &LIBCORE_TESTS_SRC.to_path(&runner.dirs),
         );
 
diff --git a/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch
deleted file mode 100644
index 161173d4765..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From f6befc4bb51d84f5f1cf35938a168c953d421350 Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Sun, 24 Nov 2019 15:10:23 +0100
-Subject: [PATCH] [core] Disable not compiling tests
-
----
- library/core/tests/Cargo.toml         | 8 ++++++++
- library/core/tests/num/flt2dec/mod.rs | 1 -
- library/core/tests/num/int_macros.rs  | 2 ++
- library/core/tests/num/uint_macros.rs | 2 ++
- library/core/tests/ptr.rs             | 2 ++
- library/core/tests/slice.rs           | 2 ++
- 6 files changed, 16 insertions(+), 1 deletion(-)
- create mode 100644 library/core/tests/Cargo.toml
-
-diff --git a/Cargo.toml b/Cargo.toml
-new file mode 100644
-index 0000000..46fd999
---- /dev/null
-+++ b/Cargo.toml
-@@ -0,0 +1,12 @@
-+[package]
-+name = "coretests"
-+version = "0.0.0"
-+edition = "2021"
-+
-+[lib]
-+name = "coretests"
-+path = "lib.rs"
-+
-+[dependencies]
-+rand = { version = "0.8.5", default-features = false }
-+rand_xorshift = { version = "0.3.0", default-features = false }
-diff --git a/lib.rs b/lib.rs
-index 42a26ae..5ac1042 100644
---- a/lib.rs
-+++ b/lib.rs
-@@ -1,3 +1,4 @@
-+#![cfg(test)]
- // tidy-alphabetical-start
- #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
- #![cfg_attr(test, feature(cfg_match))]
---
-2.21.0 (Apple Git-122)
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
index 06840624cef..4a06dc3f7ef 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
@@ -10,21 +10,20 @@ Cranelift doesn't support them yet
  library/core/tests/atomic.rs          |  4 ---
  4 files changed, 4 insertions(+), 50 deletions(-)
 
-diff --git a/lib.rs b/lib.rs
+diff --git a/tests/lib.rs b/tests/lib.rs
 index 1e336bf..35e6f54 100644
---- a/lib.rs
-+++ b/lib.rs
-@@ -2,6 +2,5 @@
- #![cfg(test)]
+--- a/tests/lib.rs
++++ b/tests/lib.rs
+@@ -2,5 +2,4 @@
  // tidy-alphabetical-start
 -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
  #![cfg_attr(test, feature(cfg_match))]
  #![feature(alloc_layout_extra)]
  #![feature(array_chunks)]
-diff --git a/atomic.rs b/atomic.rs
+diff --git a/tests/atomic.rs b/tests/atomic.rs
 index b735957..ea728b6 100644
---- a/atomic.rs
-+++ b/atomic.rs
+--- a/tests/atomic.rs
++++ b/tests/atomic.rs
 @@ -185,10 +185,6 @@ fn atomic_alignment() {
      assert_eq!(align_of::<AtomicU64>(), size_of::<AtomicU64>());
      #[cfg(target_has_atomic = "64")]
diff --git a/compiler/rustc_codegen_cranelift/patches/0028-coretests-Disable-long-running-tests.patch b/compiler/rustc_codegen_cranelift/patches/0028-coretests-Disable-long-running-tests.patch
index b98326c54a6..5a38dffa24f 100644
--- a/compiler/rustc_codegen_cranelift/patches/0028-coretests-Disable-long-running-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0028-coretests-Disable-long-running-tests.patch
@@ -7,10 +7,10 @@ Subject: [PATCH] Disable long running tests
  library/core/tests/slice.rs | 2 ++
  1 file changed, 2 insertions(+)
 
-diff --git a/slice.rs b/slice.rs
+diff --git a/tests/slice.rs b/tests/slice.rs
 index 8402833..84592e0 100644
---- a/slice.rs
-+++ b/slice.rs
+--- a/tests/slice.rs
++++ b/tests/slice.rs
 @@ -1809,6 +1809,7 @@ fn sort_unstable() {
      }
  }
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index e4c3dd708fd..9c6aad3490d 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,4 +1,4 @@
 [toolchain]
-channel = "nightly-2025-01-10"
+channel = "nightly-2025-01-20"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
 profile = "minimal"
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index e569da90cf7..41aa011e805 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -176,12 +176,11 @@ diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-supp
 index 9607ff02f96..b7d97caf9a2 100644
 --- a/src/tools/run-make-support/src/external_deps/rustdoc.rs
 +++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs
-@@ -34,8 +34,6 @@ pub fn bare() -> Self {
+@@ -34,7 +34,6 @@ pub fn bare() -> Self {
      #[track_caller]
      pub fn new() -> Self {
          let mut cmd = setup_common();
--        let target_rpath_dir = env_var_os("TARGET_RPATH_DIR");
--        cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy()));
+-        cmd.arg("-L").arg(env_var_os("TARGET_RPATH_DIR"));
          Self { cmd }
      }
 
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 2c99597922e..fdcd9caf4ac 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -126,7 +126,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
         &mut self,
         name: &str,
         params: Vec<AbiParam>,
-        returns: Vec<AbiParam>,
+        mut returns: Vec<AbiParam>,
         args: &[Value],
     ) -> Cow<'_, [Value]> {
         // Pass i128 arguments by-ref on Windows.
@@ -150,15 +150,19 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
             (params, args.into())
         };
 
-        // Return i128 using a return area pointer on Windows and s390x.
-        let adjust_ret_param =
-            if self.tcx.sess.target.is_like_windows || self.tcx.sess.target.arch == "s390x" {
-                returns.len() == 1 && returns[0].value_type == types::I128
-            } else {
-                false
-            };
+        let ret_single_i128 = returns.len() == 1 && returns[0].value_type == types::I128;
+        if ret_single_i128 && self.tcx.sess.target.is_like_windows {
+            // Return i128 using the vector ABI on Windows
+            returns[0].value_type = types::I64X2;
+
+            let ret = self.lib_call_unadjusted(name, params, returns, &args)[0];
 
-        if adjust_ret_param {
+            // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
+            let ret_ptr = self.create_stack_slot(16, 16);
+            ret_ptr.store(self, ret, MemFlags::trusted());
+            Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())])
+        } else if ret_single_i128 && self.tcx.sess.target.arch == "s390x" {
+            // Return i128 using a return area pointer on s390x.
             let mut params = params;
             let mut args = args.to_vec();
 
diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs
index 0b5cb1547fc..4463631c524 100644
--- a/compiler/rustc_codegen_cranelift/src/cast.rs
+++ b/compiler/rustc_codegen_cranelift/src/cast.rs
@@ -96,25 +96,9 @@ pub(crate) fn clif_int_or_float_cast(
                 },
             );
 
-            if fx.tcx.sess.target.is_like_windows {
-                let ret = fx.lib_call(
-                    &name,
-                    vec![AbiParam::new(from_ty)],
-                    vec![AbiParam::new(types::I64X2)],
-                    &[from],
-                )[0];
-                // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
-                let ret_ptr = fx.create_stack_slot(16, 16);
-                ret_ptr.store(fx, ret, MemFlags::trusted());
-                ret_ptr.load(fx, types::I128, MemFlags::trusted())
-            } else {
-                fx.lib_call(
-                    &name,
-                    vec![AbiParam::new(from_ty)],
-                    vec![AbiParam::new(types::I128)],
-                    &[from],
-                )[0]
-            }
+            fx.lib_call(&name, vec![AbiParam::new(from_ty)], vec![AbiParam::new(types::I128)], &[
+                from,
+            ])[0]
         } else if to_ty == types::I8 || to_ty == types::I16 {
             // FIXME implement fcvt_to_*int_sat.i8/i16
             let val = if to_signed {
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index dcfd7ddabbc..df5a79086fa 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -33,28 +33,14 @@ pub(crate) fn maybe_codegen<'tcx>(
                 (BinOp::Rem, true) => "__modti3",
                 _ => unreachable!(),
             };
-            if fx.tcx.sess.target.is_like_windows {
-                let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
-                let ret = fx.lib_call(
-                    name,
-                    vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
-                    vec![AbiParam::new(types::I64X2)],
-                    &args,
-                )[0];
-                // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
-                let ret_place = CPlace::new_stack_slot(fx, lhs.layout());
-                ret_place.to_ptr().store(fx, ret, MemFlags::trusted());
-                Some(ret_place.to_cvalue(fx))
-            } else {
-                let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
-                let ret_val = fx.lib_call(
-                    name,
-                    vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
-                    vec![AbiParam::new(types::I128)],
-                    &args,
-                )[0];
-                Some(CValue::by_val(ret_val, lhs.layout()))
-            }
+            let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
+            let ret_val = fx.lib_call(
+                name,
+                vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
+                vec![AbiParam::new(types::I128)],
+                &args,
+            )[0];
+            Some(CValue::by_val(ret_val, lhs.layout()))
         }
         BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne | BinOp::Cmp => None,
         BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index fe578e44770..27adf6318e2 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -333,9 +333,17 @@ fn make_module(sess: &Session, name: String) -> UnwindModule<ObjectModule> {
 
     let mut builder =
         ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
+
+    // Disable function sections by default on MSVC as it causes significant slowdowns with link.exe.
+    // Maybe link.exe has exponential behavior when there are many sections with the same name? Also
+    // explicitly disable it on MinGW as rustc already disables it by default on MinGW and as such
+    // isn't tested. If rustc enables it in the future on MinGW, we can re-enable it too once it has
+    // been on MinGW.
+    let default_function_sections = sess.target.function_sections && !sess.target.is_like_windows;
     builder.per_function_section(
-        sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections),
+        sess.opts.unstable_opts.function_sections.unwrap_or(default_function_sections),
     );
+
     UnwindModule::new(ObjectModule::new(builder), true)
 }
 
@@ -668,7 +676,7 @@ pub(crate) fn run_aot(
     .to_owned();
 
     let cgus = if tcx.sess.opts.output_types.should_codegen() {
-        tcx.collect_and_partition_mono_items(()).1
+        tcx.collect_and_partition_mono_items(()).codegen_units
     } else {
         // If only `--emit metadata` is used, we shouldn't perform any codegen.
         // Also `tcx.collect_and_partition_mono_items` may panic in that case.
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 2e5813556aa..26f14532b45 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -1,4 +1,5 @@
 //! Codegen of intrinsics. This includes `extern "rust-intrinsic"`,
+//! functions marked with the `#[rustc_intrinsic]` attribute
 //! and LLVM intrinsics that have symbol names starting with `llvm.`.
 
 macro_rules! intrinsic_args {
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index e6bf0d5b47e..f6843496895 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -1,7 +1,7 @@
 use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
 use rustc_hir::LangItem;
 use rustc_middle::ty::{AssocKind, GenericArg};
-use rustc_session::config::{EntryFnType, sigpipe};
+use rustc_session::config::EntryFnType;
 use rustc_span::{DUMMY_SP, Ident};
 
 use crate::prelude::*;
@@ -14,10 +14,9 @@ pub(crate) fn maybe_create_entry_wrapper(
     is_jit: bool,
     is_primary_cgu: bool,
 ) {
-    let (main_def_id, (is_main_fn, sigpipe)) = match tcx.entry_fn(()) {
+    let (main_def_id, sigpipe) = match tcx.entry_fn(()) {
         Some((def_id, entry_ty)) => (def_id, match entry_ty {
-            EntryFnType::Main { sigpipe } => (true, sigpipe),
-            EntryFnType::Start => (false, sigpipe::DEFAULT),
+            EntryFnType::Main { sigpipe } => sigpipe,
         }),
         None => return,
     };
@@ -31,14 +30,13 @@ pub(crate) fn maybe_create_entry_wrapper(
         return;
     }
 
-    create_entry_fn(tcx, module, main_def_id, is_jit, is_main_fn, sigpipe);
+    create_entry_fn(tcx, module, main_def_id, is_jit, sigpipe);
 
     fn create_entry_fn(
         tcx: TyCtxt<'_>,
         m: &mut dyn Module,
         rust_main_def_id: DefId,
         ignore_lang_start_wrapper: bool,
-        is_main_fn: bool,
         sigpipe: u8,
     ) {
         let main_ret_ty = tcx.fn_sig(rust_main_def_id).no_bound_vars().unwrap().output();
@@ -94,8 +92,8 @@ pub(crate) fn maybe_create_entry_wrapper(
 
             let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);
 
-            let result = if is_main_fn && ignore_lang_start_wrapper {
-                // regular main fn, but ignoring #[lang = "start"] as we are running in the jit
+            let result = if ignore_lang_start_wrapper {
+                // ignoring #[lang = "start"] as we are running in the jit
                 // FIXME set program arguments somehow
                 let call_inst = bcx.ins().call(main_func_ref, &[]);
                 let call_results = bcx.func.dfg.inst_results(call_inst).to_owned();
@@ -133,7 +131,8 @@ pub(crate) fn maybe_create_entry_wrapper(
                     types::I64 => bcx.ins().sextend(types::I64, res),
                     _ => unimplemented!("16bit systems are not yet supported"),
                 }
-            } else if is_main_fn {
+            } else {
+                // Regular main fn invoked via start lang item.
                 let start_def_id = tcx.require_lang_item(LangItem::Start, None);
                 let start_instance = Instance::expect_resolve(
                     tcx,
@@ -150,10 +149,6 @@ pub(crate) fn maybe_create_entry_wrapper(
                 let call_inst =
                     bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv, arg_sigpipe]);
                 bcx.inst_results(call_inst)[0]
-            } else {
-                // using user-defined start fn
-                let call_inst = bcx.ins().call(main_func_ref, &[arg_argc, arg_argv]);
-                bcx.inst_results(call_inst)[0]
             };
 
             bcx.ins().return_(&[result]);
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml
index 73ec6b84a15..f96912e6b7a 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml
@@ -13,14 +13,14 @@ env:
 
 jobs:
   build:
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-24.04
 
     strategy:
       fail-fast: false
       matrix:
         libgccjit_version:
-          - { gcc: "gcc-13.deb" }
-          - { gcc: "gcc-13-without-int128.deb" }
+          - { gcc: "gcc-15.deb" }
+          - { gcc: "gcc-15-without-int128.deb" }
         commands: [
           "--std-tests",
           # FIXME: re-enable asm tests when GCC can emit in the right syntax.
@@ -108,13 +108,13 @@ jobs:
         cargo clippy --all-targets --features master -- -D warnings
 
   duplicates:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@v4
       - run: python tools/check_intrinsics_duplicates.py
 
   build_system:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@v4
       - name: Test build system
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/failures.yml b/compiler/rustc_codegen_gcc/.github/workflows/failures.yml
index f33d9fcc582..d080bbfe91f 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/failures.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/failures.yml
@@ -13,7 +13,7 @@ env:
 
 jobs:
   build:
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-24.04
 
     strategy:
       fail-fast: false
@@ -56,12 +56,12 @@ jobs:
 
     - name: Download artifact
       if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
-      run: curl -LO https://github.com/rust-lang/gcc/releases/latest/download/gcc-13.deb
+      run: curl -LO https://github.com/rust-lang/gcc/releases/latest/download/gcc-15.deb
 
     - name: Setup path to libgccjit
       if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
       run: |
-          sudo dpkg --force-overwrite -i gcc-13.deb
+          sudo dpkg --force-overwrite -i gcc-15.deb
           echo 'gcc-path = "/usr/lib"' > config.toml
           echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
           echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml b/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml
index 4c2ce91e86e..bb9e020dc6a 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml
@@ -17,7 +17,7 @@ env:
 
 jobs:
   build:
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-24.04
 
     strategy:
       fail-fast: false
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml
index 07bb372b360..ed1fc02bd91 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml
@@ -17,7 +17,7 @@ env:
 
 jobs:
   build:
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-24.04
 
     strategy:
       fail-fast: false
@@ -47,17 +47,17 @@ jobs:
     - name: Install packages
       run: |
         sudo apt-get update
-        sudo apt-get install qemu qemu-user-static
+        sudo apt-get install qemu-system qemu-user-static
 
     - name: Download artifact
-      run: curl -LO https://github.com/cross-cg-gcc-tools/cross-gcc/releases/latest/download/gcc-m68k-13.deb
+      run: curl -LO https://github.com/cross-cg-gcc-tools/cross-gcc/releases/latest/download/gcc-m68k-15.deb
 
     - name: Download VM artifact
       run: curl -LO https://github.com/cross-cg-gcc-tools/vms/releases/latest/download/debian-m68k.img
 
     - name: Setup path to libgccjit
       run: |
-          sudo dpkg -i gcc-m68k-13.deb
+          sudo dpkg -i gcc-m68k-15.deb
           echo 'gcc-path = "/usr/lib/"' > config.toml
 
     - name: Set env
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/release.yml b/compiler/rustc_codegen_gcc/.github/workflows/release.yml
index 60e0943c87d..886ce90b471 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/release.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/release.yml
@@ -13,7 +13,7 @@ env:
 
 jobs:
   build:
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-24.04
 
     strategy:
       fail-fast: false
@@ -37,11 +37,11 @@ jobs:
       run: sudo apt-get install ninja-build ripgrep
 
     - name: Download artifact
-      run: curl -LO https://github.com/rust-lang/gcc/releases/latest/download/gcc-13.deb
+      run: curl -LO https://github.com/rust-lang/gcc/releases/latest/download/gcc-15.deb
 
     - name: Setup path to libgccjit
       run: |
-          sudo dpkg --force-overwrite -i gcc-13.deb
+          sudo dpkg --force-overwrite -i gcc-15.deb
           echo 'gcc-path = "/usr/lib/"' > config.toml
 
     - name: Set env
@@ -76,4 +76,9 @@ jobs:
     - name: Run y.sh cargo build
       run: |
         EMBED_LTO_BITCODE=1 CHANNEL="release" ./y.sh cargo build --release --manifest-path tests/hello-world/Cargo.toml
-        # TODO: grep the asm output for "call my_func" and fail if it is found.
+        call_found=$(objdump -dj .text tests/hello-world/target/release/hello_world | grep -c "call .*mylib.*my_func" ) ||:
+        if [ $call_found -gt 0 ]; then
+          echo "ERROR: call my_func found in asm"
+          echo "Test is done with LTO enabled, hence inlining should occur across crates"
+          exit 1
+        fi
diff --git a/compiler/rustc_codegen_gcc/build_system/src/build.rs b/compiler/rustc_codegen_gcc/build_system/src/build.rs
index d0ced211a61..e98377f15a9 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/build.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/build.rs
@@ -150,6 +150,8 @@ pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Resu
         "debug"
     };
 
+    // We have a different environment variable than RUSTFLAGS to make sure those flags are only
+    // sent to rustc_codegen_gcc and not the LLVM backend.
     if let Ok(cg_rustflags) = std::env::var("CG_RUSTFLAGS") {
         rustflags.push(' ');
         rustflags.push_str(&cg_rustflags);
@@ -184,8 +186,12 @@ pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Resu
 fn build_codegen(args: &mut BuildArg) -> Result<(), String> {
     let mut env = HashMap::new();
 
-    env.insert("LD_LIBRARY_PATH".to_string(), args.config_info.gcc_path.clone());
-    env.insert("LIBRARY_PATH".to_string(), args.config_info.gcc_path.clone());
+    let gcc_path =
+        args.config_info.gcc_path.clone().expect(
+            "The config module should have emitted an error if the GCC path wasn't provided",
+        );
+    env.insert("LD_LIBRARY_PATH".to_string(), gcc_path.clone());
+    env.insert("LIBRARY_PATH".to_string(), gcc_path);
 
     if args.config_info.no_default_features {
         env.insert("RUSTFLAGS".to_string(), "-Csymbol-mangling-version=v0".to_string());
diff --git a/compiler/rustc_codegen_gcc/build_system/src/config.rs b/compiler/rustc_codegen_gcc/build_system/src/config.rs
index 37b4b68950e..4f9fcc97151 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/config.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/config.rs
@@ -112,7 +112,7 @@ pub struct ConfigInfo {
     pub sysroot_panic_abort: bool,
     pub cg_backend_path: String,
     pub sysroot_path: String,
-    pub gcc_path: String,
+    pub gcc_path: Option<String>,
     config_file: Option<String>,
     // This is used in particular in rust compiler bootstrap because it doesn't run at the root
     // of the `cg_gcc` folder, making it complicated for us to get access to local files we need
@@ -173,6 +173,14 @@ impl ConfigInfo {
             "--release-sysroot" => self.sysroot_release_channel = true,
             "--release" => self.channel = Channel::Release,
             "--sysroot-panic-abort" => self.sysroot_panic_abort = true,
+            "--gcc-path" => match args.next() {
+                Some(arg) if !arg.is_empty() => {
+                    self.gcc_path = Some(arg.into());
+                }
+                _ => {
+                    return Err("Expected a value after `--gcc-path`, found nothing".to_string());
+                }
+            },
             "--cg_gcc-path" => match args.next() {
                 Some(arg) if !arg.is_empty() => {
                     self.cg_gcc_path = Some(arg.into());
@@ -260,8 +268,9 @@ impl ConfigInfo {
             create_symlink(&libgccjit_so, output_dir.join(&format!("{}.0", libgccjit_so_name)))?;
         }
 
-        self.gcc_path = output_dir.display().to_string();
-        println!("Using `{}` as path for libgccjit", self.gcc_path);
+        let gcc_path = output_dir.display().to_string();
+        println!("Using `{}` as path for libgccjit", gcc_path);
+        self.gcc_path = Some(gcc_path);
         Ok(())
     }
 
@@ -273,6 +282,15 @@ impl ConfigInfo {
     }
 
     pub fn setup_gcc_path(&mut self) -> Result<(), String> {
+        // If the user used the `--gcc-path` option, no need to look at `config.toml` content
+        // since we already have everything we need.
+        if let Some(gcc_path) = &self.gcc_path {
+            println!(
+                "`--gcc-path` was provided, ignoring config file. Using `{}` as path for libgccjit",
+                gcc_path
+            );
+            return Ok(());
+        }
         let config_file = match self.config_file.as_deref() {
             Some(config_file) => config_file.into(),
             None => self.compute_path("config.toml"),
@@ -283,12 +301,15 @@ impl ConfigInfo {
             self.download_gccjit_if_needed()?;
             return Ok(());
         }
-        self.gcc_path = match gcc_path {
-            Some(path) => path,
-            None => {
-                return Err(format!("missing `gcc-path` value from `{}`", config_file.display(),));
-            }
+        let Some(gcc_path) = gcc_path else {
+            return Err(format!("missing `gcc-path` value from `{}`", config_file.display()));
         };
+        println!(
+            "GCC path retrieved from `{}`. Using `{}` as path for libgccjit",
+            config_file.display(),
+            gcc_path
+        );
+        self.gcc_path = Some(gcc_path);
         Ok(())
     }
 
@@ -299,10 +320,17 @@ impl ConfigInfo {
     ) -> Result<(), String> {
         env.insert("CARGO_INCREMENTAL".to_string(), "0".to_string());
 
-        if self.gcc_path.is_empty() && !use_system_gcc {
-            self.setup_gcc_path()?;
-        }
-        env.insert("GCC_PATH".to_string(), self.gcc_path.clone());
+        let gcc_path = if !use_system_gcc {
+            if self.gcc_path.is_none() {
+                self.setup_gcc_path()?;
+            }
+            self.gcc_path.clone().expect(
+                "The config module should have emitted an error if the GCC path wasn't provided",
+            )
+        } else {
+            String::new()
+        };
+        env.insert("GCC_PATH".to_string(), gcc_path.clone());
 
         if self.cargo_target_dir.is_empty() {
             match env.get("CARGO_TARGET_DIR").filter(|dir| !dir.is_empty()) {
@@ -381,6 +409,8 @@ impl ConfigInfo {
         }
 
         // This environment variable is useful in case we want to change options of rustc commands.
+        // We have a different environment variable than RUSTFLAGS to make sure those flags are
+        // only sent to rustc_codegen_gcc and not the LLVM backend.
         if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") {
             rustflags.extend_from_slice(&split_args(&cg_rustflags)?);
         }
@@ -414,7 +444,7 @@ impl ConfigInfo {
             "{target}:{sysroot}:{gcc_path}",
             target = self.cargo_target_dir,
             sysroot = sysroot.display(),
-            gcc_path = self.gcc_path,
+            gcc_path = gcc_path,
         );
         env.insert("LIBRARY_PATH".to_string(), ld_library_path.clone());
         env.insert("LD_LIBRARY_PATH".to_string(), ld_library_path.clone());
@@ -459,6 +489,7 @@ impl ConfigInfo {
     --release-sysroot      : Build sysroot in release mode
     --sysroot-panic-abort  : Build the sysroot without unwinding support
     --config-file          : Location of the config file to be used
+    --gcc-path             : Location of the GCC root folder
     --cg_gcc-path          : Location of the rustc_codegen_gcc root folder (used
                              when ran from another directory)
     --no-default-features  : Add `--no-default-features` flag to cargo commands
diff --git a/compiler/rustc_codegen_gcc/build_system/src/info.rs b/compiler/rustc_codegen_gcc/build_system/src/info.rs
index ea38791d38c..bd891de2eb4 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/info.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/info.rs
@@ -14,6 +14,8 @@ pub fn run() -> Result<(), String> {
     }
     config.no_download = true;
     config.setup_gcc_path()?;
-    println!("{}", config.gcc_path);
+    if let Some(gcc_path) = config.gcc_path {
+        println!("{}", gcc_path);
+    }
     Ok(())
 }
diff --git a/compiler/rustc_codegen_gcc/build_system/src/main.rs b/compiler/rustc_codegen_gcc/build_system/src/main.rs
index 3a860e2b136..39361718306 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/main.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/main.rs
@@ -34,11 +34,11 @@ Options:
         --help    : Displays this help message.
 
 Commands:
-        cargo     : Executes a cargo command. 
+        cargo     : Executes a cargo command.
         rustc     : Compiles the program using the GCC compiler.
         clean     : Cleans the build directory, removing all compiled files and artifacts.
         prepare   : Prepares the environment for building, including fetching dependencies and setting up configurations.
-        build     : Compiles the project. 
+        build     : Compiles the project.
         test      : Runs tests for the project.
         info      : Displays information about the build environment and project configuration.
         clone-gcc : Clones the GCC compiler from a specified source.
diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs
index 7cc7336612c..6c29c7d1825 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/test.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs
@@ -426,19 +426,6 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> {
     run_command_with_env(&command, None, Some(env))?;
     maybe_run_command_in_vm(&[&cargo_target_dir.join("track-caller-attribute")], env, args)?;
 
-    // FIXME: create a function "display_if_not_quiet" or something along the line.
-    println!("[AOT] mod_bench");
-    let mut command = args.config_info.rustc_command_vec();
-    command.extend_from_slice(&[
-        &"example/mod_bench.rs",
-        &"--crate-type",
-        &"bin",
-        &"--target",
-        &args.config_info.target_triple,
-    ]);
-    run_command_with_env(&command, None, Some(env))?;
-    // FIXME: the compiled binary is not run.
-
     Ok(())
 }
 
@@ -696,19 +683,6 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> {
     Ok(())
 }
 
-// echo "[BENCH COMPILE] mod_bench"
-//
-// COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline"
-// COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o $cargo_target_dir/mod_bench_llvm_0 -Cpanic=abort"
-// COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o $cargo_target_dir/mod_bench_llvm_1 -Cpanic=abort"
-// COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o $cargo_target_dir/mod_bench_llvm_2 -Cpanic=abort"
-// COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o $cargo_target_dir/mod_bench_llvm_3 -Cpanic=abort"
-//
-// Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow
-// hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3"
-// echo "[BENCH RUN] mod_bench"
-// hyperfine --runs ${RUN_RUNS:-10} $cargo_target_dir/mod_bench{,_inline} $cargo_target_dir/mod_bench_llvm_*
-
 fn extended_rand_tests(env: &Env, args: &TestArg) -> Result<(), String> {
     if !args.is_using_gcc_master_branch() {
         println!("Not using GCC master branch. Skipping `extended_rand_tests`.");
@@ -1255,8 +1229,11 @@ pub fn run() -> Result<(), String> {
 
     if !args.use_system_gcc {
         args.config_info.setup_gcc_path()?;
-        env.insert("LIBRARY_PATH".to_string(), args.config_info.gcc_path.clone());
-        env.insert("LD_LIBRARY_PATH".to_string(), args.config_info.gcc_path.clone());
+        let gcc_path = args.config_info.gcc_path.clone().expect(
+            "The config module should have emitted an error if the GCC path wasn't provided",
+        );
+        env.insert("LIBRARY_PATH".to_string(), gcc_path.clone());
+        env.insert("LD_LIBRARY_PATH".to_string(), gcc_path);
     }
 
     build_if_no_backend(&env, &args)?;
diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs
index 6ed8b9157f2..9a0b46d5b22 100644
--- a/compiler/rustc_codegen_gcc/example/alloc_example.rs
+++ b/compiler/rustc_codegen_gcc/example/alloc_example.rs
@@ -1,5 +1,6 @@
-#![feature(start, core_intrinsics, alloc_error_handler, lang_items)]
+#![feature(core_intrinsics, alloc_error_handler, lang_items)]
 #![no_std]
+#![no_main]
 #![allow(internal_features)]
 
 extern crate alloc;
@@ -37,8 +38,8 @@ unsafe extern "C" fn _Unwind_Resume() {
     core::intrinsics::unreachable();
 }
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     let world: Box<&str> = Box::new("Hello World!\0");
     unsafe {
         puts(*world as *const str as *const u8);
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
index 1d51e0a1856..4cbe66c5e4c 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -1,7 +1,7 @@
 // Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs
 
 #![feature(
-    no_core, unboxed_closures, start, lang_items, never_type, linkage,
+    no_core, unboxed_closures, lang_items, never_type, linkage,
     extern_types, thread_local
 )]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/example/mod_bench.rs b/compiler/rustc_codegen_gcc/example/mod_bench.rs
deleted file mode 100644
index e8a9cade747..00000000000
--- a/compiler/rustc_codegen_gcc/example/mod_bench.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-#![feature(start, core_intrinsics, lang_items)]
-#![no_std]
-#![allow(internal_features)]
-
-#[link(name = "c")]
-extern "C" {}
-
-#[panic_handler]
-fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! {
-    core::intrinsics::abort();
-}
-
-#[lang="eh_personality"]
-fn eh_personality(){}
-
-// Required for rustc_codegen_llvm
-#[no_mangle]
-unsafe extern "C" fn _Unwind_Resume() {
-    core::intrinsics::unreachable();
-}
-
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
-    for i in 2..100_000_000 {
-        black_box((i + 1) % i);
-    }
-
-    0
-}
-
-#[inline(never)]
-fn black_box(i: u32) {
-    if i != 1 {
-        core::intrinsics::abort();
-    }
-}
diff --git a/compiler/rustc_codegen_gcc/libgccjit.version b/compiler/rustc_codegen_gcc/libgccjit.version
index ff58accec1d..417fd5b0393 100644
--- a/compiler/rustc_codegen_gcc/libgccjit.version
+++ b/compiler/rustc_codegen_gcc/libgccjit.version
@@ -1 +1 @@
-45648c2edd4ecd862d9f08196d3d6c6ccba79f07
+e607be166673a8de9fc07f6f02c60426e556c5f2
diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl
index 85fa17a6ba5..882fff8673a 100644
--- a/compiler/rustc_codegen_gcc/messages.ftl
+++ b/compiler/rustc_codegen_gcc/messages.ftl
@@ -5,9 +5,6 @@ codegen_gcc_unknown_ctarget_feature_prefix =
 codegen_gcc_invalid_minimum_alignment =
     invalid minimum global alignment: {$err}
 
-codegen_gcc_lto_not_supported =
-    LTO is not supported. You may get a linker error.
-
 codegen_gcc_forbidden_ctarget_feature =
     target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
 
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index f43743fc2a4..bd5d6ba387c 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -64,6 +64,11 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) }
     }
 
+    fn is_undef(&self, _val: RValue<'gcc>) -> bool {
+        // FIXME: actually check for undef
+        false
+    }
+
     fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> {
         let local = self.current_func.borrow().expect("func").new_local(None, typ, "undefined");
         if typ.is_struct().is_some() {
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index c81c53359fd..30732c74eb3 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -513,7 +513,6 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         } else {
             // If the symbol already exists, it is an error: for example, the user wrote
             // #[no_mangle] extern "C" fn main(..) {..}
-            // instead of #[start]
             None
         }
     }
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs
index d3aeb7f3bde..4b84b1dbfd3 100644
--- a/compiler/rustc_codegen_gcc/src/debuginfo.rs
+++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs
@@ -113,15 +113,15 @@ fn make_mir_scope<'gcc, 'tcx>(
     let scope_data = &mir.source_scopes[scope];
     let parent_scope = if let Some(parent) = scope_data.parent_scope {
         make_mir_scope(cx, _instance, mir, variables, debug_context, instantiated, parent);
-        debug_context.scopes[parent].unwrap()
+        debug_context.scopes[parent]
     } else {
         // The root is the function itself.
         let file = cx.sess().source_map().lookup_source_file(mir.span.lo());
-        debug_context.scopes[scope] = Some(DebugScope {
+        debug_context.scopes[scope] = DebugScope {
             file_start_pos: file.start_pos,
             file_end_pos: file.end_position(),
-            ..debug_context.scopes[scope].unwrap()
-        });
+            ..debug_context.scopes[scope]
+        };
         instantiated.insert(scope);
         return;
     };
@@ -130,7 +130,7 @@ fn make_mir_scope<'gcc, 'tcx>(
         if !vars.contains(scope) && scope_data.inlined.is_none() {
             // Do not create a DIScope if there are no variables defined in this
             // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
-            debug_context.scopes[scope] = Some(parent_scope);
+            debug_context.scopes[scope] = parent_scope;
             instantiated.insert(scope);
             return;
         }
@@ -157,12 +157,12 @@ fn make_mir_scope<'gcc, 'tcx>(
     // TODO(tempdragon): dbg_scope: Add support for scope extension here.
     inlined_at.or(p_inlined_at);
 
-    debug_context.scopes[scope] = Some(DebugScope {
+    debug_context.scopes[scope] = DebugScope {
         dbg_scope,
         inlined_at,
         file_start_pos: loc.file.start_pos,
         file_end_pos: loc.file.end_position(),
-    });
+    };
     instantiated.insert(scope);
 }
 
@@ -232,12 +232,12 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         }
 
         // Initialize fn debug context (including scopes).
-        let empty_scope = Some(DebugScope {
+        let empty_scope = DebugScope {
             dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
             inlined_at: None,
             file_start_pos: BytePos(0),
             file_end_pos: BytePos(0),
-        });
+        };
         let mut fn_debug_context = FunctionDebugContext {
             scopes: IndexVec::from_elem(empty_scope, mir.source_scopes.as_slice()),
             inlined_function_scopes: Default::default(),
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index f6ad0c79de5..38019faa7a9 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -444,7 +444,6 @@ impl WriteBackendMethods for GccCodegenBackend {
     }
     fn autodiff(
         _cgcx: &CodegenContext<Self>,
-        _tcx: TyCtxt<'_>,
         _module: &ModuleCodegen<Self::Module>,
         _diff_fncs: Vec<AutoDiffItem>,
         _config: &ModuleConfig,
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
index 696197d7377..385e41a6881 100644
--- a/compiler/rustc_codegen_gcc/tests/run/abort1.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: signal
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -49,7 +50,7 @@ fn test_fail() -> ! {
     unsafe { intrinsics::abort() };
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     test_fail();
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
index 714cd6c0f38..6c66a930e07 100644
--- a/compiler/rustc_codegen_gcc/tests/run/abort2.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: signal
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -50,8 +51,8 @@ fn fail() -> i32 {
     0
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     fail();
     0
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs
index c3c08c29c6d..e18a4ced6bc 100644
--- a/compiler/rustc_codegen_gcc/tests/run/array.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/array.rs
@@ -7,10 +7,11 @@
 //     5
 //     10
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -28,8 +29,8 @@ fn make_array() -> [u8; 3] {
     [42, 10, 5]
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let array = [42, 7, 5];
     let array2 = make_array();
     unsafe {
diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs
index 2a47f0c2966..4d414c577a6 100644
--- a/compiler/rustc_codegen_gcc/tests/run/assign.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs
@@ -6,10 +6,11 @@
 //     10
 
 #![allow(internal_features, unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -142,8 +143,8 @@ fn inc(num: isize) -> isize {
 }
 
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     argc = inc(argc);
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs
index 46c47bc54ed..c7a236f74f9 100644
--- a/compiler/rustc_codegen_gcc/tests/run/closure.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/closure.rs
@@ -8,10 +8,11 @@
 //     Int argument: 2
 //     Both args: 11
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -22,8 +23,8 @@ mod libc {
     }
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let string = "Arg: %d\n\0";
     let mut closure = || {
         unsafe {
diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs
index 039ef94eaa7..b02359702ed 100644
--- a/compiler/rustc_codegen_gcc/tests/run/condition.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/condition.rs
@@ -5,10 +5,11 @@
 //   stdout: true
 //     1
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -19,8 +20,8 @@ mod libc {
     }
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         if argc == 1 {
             libc::printf(b"true\n\0" as *const u8 as *const i8);
diff --git a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
index e66a859ad69..042e44080c5 100644
--- a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: 0
 
-#![feature(auto_traits, lang_items, no_core, start)]
+#![feature(auto_traits, lang_items, no_core)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -34,7 +35,7 @@ pub(crate) unsafe auto trait Freeze {}
  * Code
  */
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     0
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit.rs b/compiler/rustc_codegen_gcc/tests/run/exit.rs
index bf1cbeef302..9a7c91c0adb 100644
--- a/compiler/rustc_codegen_gcc/tests/run/exit.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/exit.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: 2
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, intrinsics)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 mod libc {
     #[link(name = "c")]
@@ -41,8 +42,8 @@ pub(crate) unsafe auto trait Freeze {}
  * Code
  */
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         libc::exit(2);
     }
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
index be7a233efda..c50d2b0d710 100644
--- a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: 1
 
-#![feature(auto_traits, lang_items, no_core, start)]
+#![feature(auto_traits, lang_items, no_core)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -34,7 +35,7 @@ pub(crate) unsafe auto trait Freeze {}
  * Code
  */
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     1
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
index ed1bf72bb27..98b351e5044 100644
--- a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
@@ -4,10 +4,11 @@
 //   status: 0
 //   stdout: 1
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -26,8 +27,8 @@ fn call_func(func: fn(i16) -> i8, param: i16) -> i8 {
     func(param)
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         let result = call_func(i16_as_i8, argc as i16) as isize;
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, result);
diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
index 3ae79338216..9be64f991ee 100644
--- a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
@@ -8,10 +8,11 @@
 //     11
 
 #![allow(internal_features, unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -148,8 +149,8 @@ fn update_num(num: &mut isize) {
     *num = *num + 5;
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let mut test = test(argc);
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field);
diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs
index 0e44fc580b8..c92d3cc0b8f 100644
--- a/compiler/rustc_codegen_gcc/tests/run/operations.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs
@@ -6,10 +6,11 @@
 //     10
 
 #![allow(internal_features, unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types, rustc_attrs)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, arbitrary_self_types, rustc_attrs)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -231,8 +232,8 @@ pub fn panic_const_mul_overflow() -> ! {
  * Code
  */
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 + argc);
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 - argc);
diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
index 2b8812ad51c..0ba49e7187f 100644
--- a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
@@ -4,10 +4,11 @@
 //   status: 0
 //   stdout: 1
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -24,8 +25,8 @@ fn make_array() -> [u8; 3] {
     [42, 10, 5]
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         let ptr = ONE as *mut usize;
         let value = ptr as usize;
diff --git a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
index f2a5a2e4384..3cc1e274001 100644
--- a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
@@ -6,11 +6,12 @@
 //     10
 //     42
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, intrinsics)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 #[lang = "copy"]
 pub unsafe trait Copy {}
@@ -61,8 +62,8 @@ fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u3
     )
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42);
     unsafe {
         libc::printf(b"%d\n\0" as *const u8 as *const i8, c);
diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs
index fba93fc1554..825fcb8a081 100644
--- a/compiler/rustc_codegen_gcc/tests/run/slice.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/slice.rs
@@ -4,10 +4,11 @@
 //   status: 0
 //   stdout: 5
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -26,8 +27,8 @@ fn index_slice(s: &[u32]) -> u32 {
     }
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let array = [42, 7, 5];
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, index_slice(&array));
diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs
index a17ea2a4893..80c8782c4b1 100644
--- a/compiler/rustc_codegen_gcc/tests/run/static.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/static.rs
@@ -9,11 +9,12 @@
 //      12
 //      1
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -98,8 +99,8 @@ static mut WITH_REF: WithRef = WithRef {
     refe: unsafe { &TEST },
 };
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, CONSTANT);
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field);
diff --git a/compiler/rustc_codegen_gcc/tests/run/structs.rs b/compiler/rustc_codegen_gcc/tests/run/structs.rs
index d6455667400..59b8f358863 100644
--- a/compiler/rustc_codegen_gcc/tests/run/structs.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/structs.rs
@@ -5,11 +5,12 @@
 //   stdout: 1
 //     2
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, intrinsics)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -55,8 +56,8 @@ fn one() -> isize {
     1
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let test = Test {
         field: one(),
     };
diff --git a/compiler/rustc_codegen_gcc/tests/run/tuple.rs b/compiler/rustc_codegen_gcc/tests/run/tuple.rs
index 8a7d85ae867..ed60a56a68c 100644
--- a/compiler/rustc_codegen_gcc/tests/run/tuple.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/tuple.rs
@@ -4,11 +4,12 @@
 //   status: 0
 //   stdout: 3
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, intrinsics)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -42,8 +43,8 @@ mod libc {
  * Code
  */
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let test: (isize, isize, isize) = (3, 1, 4);
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.0);
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index c44d1a5e5c2..94f21ac5f57 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -9,6 +9,8 @@ test = false
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
+# To avoid duplicate dependencies, this should match the version of gimli used
+# by `rustc_codegen_ssa` via its `thorin-dwp` dependency.
 gimli = "0.30"
 itertools = "0.12"
 libc = "0.2"
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 95e0481b035..3d7afa17bdf 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -333,9 +333,12 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
     let mut to_add = SmallVec::<[_; 16]>::new();
 
     match codegen_fn_attrs.optimize {
-        OptimizeAttr::None => {
+        OptimizeAttr::Default => {
             to_add.extend(default_optimisation_attrs(cx));
         }
+        OptimizeAttr::DoNotOptimize => {
+            to_add.push(llvm::AttributeKind::OptimizeNone.create_attr(cx.llcx));
+        }
         OptimizeAttr::Size => {
             to_add.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx));
             to_add.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
@@ -343,12 +346,12 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
         OptimizeAttr::Speed => {}
     }
 
-    let inline =
-        if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
-            InlineAttr::Hint
-        } else {
-            codegen_fn_attrs.inline
-        };
+    // `optnone` requires `noinline`
+    let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) {
+        (_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never,
+        (InlineAttr::None, _) if instance.def.requires_inline(cx.tcx) => InlineAttr::Hint,
+        (inline, _) => inline,
+    };
     to_add.extend(inline_attr(cx, inline));
 
     // The `uwtable` attribute according to LLVM is:
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 509b24dd703..4706744f353 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -769,12 +769,9 @@ pub(crate) unsafe fn codegen(
             }
         }
 
-        // Two things to note:
-        // - If object files are just LLVM bitcode we write bitcode, copy it to
-        //   the .o file, and delete the bitcode if it wasn't otherwise
-        //   requested.
-        // - If we don't have the integrated assembler then we need to emit
-        //   asm from LLVM and use `gcc` to create the object file.
+        // Note that if object files are just LLVM bitcode we write bitcode,
+        // copy it to the .o file, and delete the bitcode if it wasn't
+        // otherwise requested.
 
         let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
         let bc_summary_out =
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 5a34b52e6ef..d2de62b17f0 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1,4 +1,4 @@
-use std::borrow::Cow;
+use std::borrow::{Borrow, Cow};
 use std::ops::Deref;
 use std::{iter, ptr};
 
@@ -31,20 +31,22 @@ use tracing::{debug, instrument};
 use crate::abi::FnAbiLlvmExt;
 use crate::attributes;
 use crate::common::Funclet;
-use crate::context::CodegenCx;
+use crate::context::{CodegenCx, SimpleCx};
 use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, True};
 use crate::type_::Type;
 use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
 
-// All Builders must have an llfn associated with them
 #[must_use]
-pub(crate) struct Builder<'a, 'll, 'tcx> {
+pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow<SimpleCx<'ll>>> {
     pub llbuilder: &'ll mut llvm::Builder<'ll>,
-    pub cx: &'a CodegenCx<'ll, 'tcx>,
+    pub cx: &'a CX,
 }
 
-impl Drop for Builder<'_, '_, '_> {
+pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SimpleCx<'ll>>;
+pub(crate) type Builder<'a, 'll, 'tcx> = GenericBuilder<'a, 'll, CodegenCx<'ll, 'tcx>>;
+
+impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> Drop for GenericBuilder<'a, 'll, CX> {
     fn drop(&mut self) {
         unsafe {
             llvm::LLVMDisposeBuilder(&mut *(self.llbuilder as *mut _));
@@ -52,6 +54,112 @@ impl Drop for Builder<'_, '_, '_> {
     }
 }
 
+impl<'a, 'll> SBuilder<'a, 'll> {
+    fn call(
+        &mut self,
+        llty: &'ll Type,
+        llfn: &'ll Value,
+        args: &[&'ll Value],
+        funclet: Option<&Funclet<'ll>>,
+    ) -> &'ll Value {
+        debug!("call {:?} with args ({:?})", llfn, args);
+
+        let args = self.check_call("call", llty, llfn, args);
+        let funclet_bundle = funclet.map(|funclet| funclet.bundle());
+        let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
+        if let Some(funclet_bundle) = funclet_bundle {
+            bundles.push(funclet_bundle);
+        }
+
+        let call = unsafe {
+            llvm::LLVMBuildCallWithOperandBundles(
+                self.llbuilder,
+                llty,
+                llfn,
+                args.as_ptr() as *const &llvm::Value,
+                args.len() as c_uint,
+                bundles.as_ptr(),
+                bundles.len() as c_uint,
+                c"".as_ptr(),
+            )
+        };
+        call
+    }
+
+    fn with_scx(scx: &'a SimpleCx<'ll>) -> Self {
+        // Create a fresh builder from the simple context.
+        let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.llcx) };
+        SBuilder { llbuilder, cx: scx }
+    }
+}
+impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+    pub(crate) fn bitcast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
+        unsafe { llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED) }
+    }
+
+    fn ret_void(&mut self) {
+        unsafe {
+            llvm::LLVMBuildRetVoid(self.llbuilder);
+        }
+    }
+
+    fn ret(&mut self, v: &'ll Value) {
+        unsafe {
+            llvm::LLVMBuildRet(self.llbuilder, v);
+        }
+    }
+}
+impl<'a, 'll> SBuilder<'a, 'll> {
+    fn build(cx: &'a SimpleCx<'ll>, llbb: &'ll BasicBlock) -> SBuilder<'a, 'll> {
+        let bx = SBuilder::with_scx(cx);
+        unsafe {
+            llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb);
+        }
+        bx
+    }
+
+    fn check_call<'b>(
+        &mut self,
+        typ: &str,
+        fn_ty: &'ll Type,
+        llfn: &'ll Value,
+        args: &'b [&'ll Value],
+    ) -> Cow<'b, [&'ll Value]> {
+        assert!(
+            self.cx.type_kind(fn_ty) == TypeKind::Function,
+            "builder::{typ} not passed a function, but {fn_ty:?}"
+        );
+
+        let param_tys = self.cx.func_params_types(fn_ty);
+
+        let all_args_match = iter::zip(&param_tys, args.iter().map(|&v| self.cx.val_ty(v)))
+            .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);
+
+        if all_args_match {
+            return Cow::Borrowed(args);
+        }
+
+        let casted_args: Vec<_> = iter::zip(param_tys, args)
+            .enumerate()
+            .map(|(i, (expected_ty, &actual_val))| {
+                let actual_ty = self.cx.val_ty(actual_val);
+                if expected_ty != actual_ty {
+                    debug!(
+                        "type mismatch in function call of {:?}. \
+                            Expected {:?} for param {}, got {:?}; injecting bitcast",
+                        llfn, expected_ty, i, actual_ty
+                    );
+                    self.bitcast(actual_val, expected_ty)
+                } else {
+                    actual_val
+                }
+            })
+            .collect();
+
+        Cow::Owned(casted_args)
+    }
+}
+
 /// Empty string, to be used where LLVM expects an instruction name, indicating
 /// that the instruction is to be left unnamed (i.e. numbered, in textual IR).
 // FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer.
@@ -1222,6 +1330,14 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> {
 }
 
 impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
+    fn build(cx: &'a CodegenCx<'ll, 'tcx>, llbb: &'ll BasicBlock) -> Builder<'a, 'll, 'tcx> {
+        let bx = Builder::with_cx(cx);
+        unsafe {
+            llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb);
+        }
+        bx
+    }
+
     fn with_cx(cx: &'a CodegenCx<'ll, 'tcx>) -> Self {
         // Create a fresh builder from the crate context.
         let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(cx.llcx) };
@@ -1231,13 +1347,16 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
     pub(crate) fn llfn(&self) -> &'ll Value {
         unsafe { llvm::LLVMGetBasicBlockParent(self.llbb()) }
     }
+}
 
+impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
     fn position_at_start(&mut self, llbb: &'ll BasicBlock) {
         unsafe {
             llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb);
         }
     }
-
+}
+impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
     fn align_metadata(&mut self, load: &'ll Value, align: Align) {
         unsafe {
             let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))];
@@ -1259,7 +1378,8 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
             self.set_metadata(inst, llvm::MD_unpredictable, md);
         }
     }
-
+}
+impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
     pub(crate) fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
         unsafe { llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) }
     }
@@ -1360,7 +1480,9 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         let ret = unsafe { llvm::LLVMBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) };
         ret.expect("LLVM does not have support for catchret")
     }
+}
 
+impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
     fn check_call<'b>(
         &mut self,
         typ: &str,
@@ -1401,11 +1523,13 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
 
         Cow::Owned(casted_args)
     }
-
+}
+impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
     pub(crate) fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) }
     }
-
+}
+impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
     pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
         let (ty, f) = self.cx.get_intrinsic(intrinsic);
         self.call(ty, None, None, f, args, None, None)
@@ -1423,7 +1547,8 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
 
         self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]);
     }
-
+}
+impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
     pub(crate) fn phi(
         &mut self,
         ty: &'ll Type,
@@ -1443,7 +1568,8 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
             llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint);
         }
     }
-
+}
+impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
     fn fptoint_sat(&mut self, signed: bool, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
         let src_ty = self.cx.val_ty(val);
         let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector {
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index 38f7eaa090f..6b17b5f6989 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -3,20 +3,19 @@ use std::ptr;
 use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode};
 use rustc_codegen_ssa::ModuleCodegen;
 use rustc_codegen_ssa::back::write::ModuleConfig;
-use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods};
 use rustc_errors::FatalError;
-use rustc_middle::ty::TyCtxt;
 use rustc_session::config::Lto;
 use tracing::{debug, trace};
 
 use crate::back::write::{llvm_err, llvm_optimize};
-use crate::builder::Builder;
-use crate::declare::declare_raw_fn;
+use crate::builder::SBuilder;
+use crate::context::SimpleCx;
+use crate::declare::declare_simple_fn;
 use crate::errors::LlvmError;
 use crate::llvm::AttributePlace::Function;
 use crate::llvm::{Metadata, True};
 use crate::value::Value;
-use crate::{CodegenContext, LlvmCodegenBackend, ModuleLlvm, attributes, context, llvm};
+use crate::{CodegenContext, LlvmCodegenBackend, ModuleLlvm, attributes, llvm};
 
 fn get_params(fnc: &Value) -> Vec<&Value> {
     unsafe {
@@ -38,8 +37,8 @@ fn get_params(fnc: &Value) -> Vec<&Value> {
 /// [^1]: <https://enzyme.mit.edu/getting_started/CallingConvention/>
 // FIXME(ZuseZ4): `outer_fn` should include upstream safety checks to
 // cover some assumptions of enzyme/autodiff, which could lead to UB otherwise.
-fn generate_enzyme_call<'ll, 'tcx>(
-    cx: &context::CodegenCx<'ll, 'tcx>,
+fn generate_enzyme_call<'ll>(
+    cx: &SimpleCx<'ll>,
     fn_to_diff: &'ll Value,
     outer_fn: &'ll Value,
     attrs: AutoDiffAttrs,
@@ -112,7 +111,7 @@ fn generate_enzyme_call<'ll, 'tcx>(
         //FIXME(ZuseZ4): the CC/Addr/Vis values are best effort guesses, we should look at tests and
         // think a bit more about what should go here.
         let cc = llvm::LLVMGetFunctionCallConv(outer_fn);
-        let ad_fn = declare_raw_fn(
+        let ad_fn = declare_simple_fn(
             cx,
             &ad_name,
             llvm::CallConv::try_from(cc).expect("invalid callconv"),
@@ -132,7 +131,7 @@ fn generate_enzyme_call<'ll, 'tcx>(
         llvm::LLVMRustEraseInstFromParent(br);
 
         let last_inst = llvm::LLVMRustGetLastInstruction(entry).unwrap();
-        let mut builder = Builder::build(cx, entry);
+        let mut builder = SBuilder::build(cx, entry);
 
         let num_args = llvm::LLVMCountParams(&fn_to_diff);
         let mut args = Vec::with_capacity(num_args as usize + 1);
@@ -236,7 +235,7 @@ fn generate_enzyme_call<'ll, 'tcx>(
             }
         }
 
-        let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None);
+        let call = builder.call(enzyme_ty, ad_fn, &args, None);
 
         // This part is a bit iffy. LLVM requires that a call to an inlineable function has some
         // metadata attachted to it, but we just created this code oota. Given that the
@@ -274,10 +273,9 @@ fn generate_enzyme_call<'ll, 'tcx>(
     }
 }
 
-pub(crate) fn differentiate<'ll, 'tcx>(
+pub(crate) fn differentiate<'ll>(
     module: &'ll ModuleCodegen<ModuleLlvm>,
     cgcx: &CodegenContext<LlvmCodegenBackend>,
-    tcx: TyCtxt<'tcx>,
     diff_items: Vec<AutoDiffItem>,
     config: &ModuleConfig,
 ) -> Result<(), FatalError> {
@@ -286,8 +284,7 @@ pub(crate) fn differentiate<'ll, 'tcx>(
     }
 
     let diag_handler = cgcx.create_dcx();
-    let (_, cgus) = tcx.collect_and_partition_mono_items(());
-    let cx = context::CodegenCx::new(tcx, &cgus.first().unwrap(), &module.module_llvm);
+    let cx = SimpleCx { llmod: module.module_llvm.llmod(), llcx: module.module_llvm.llcx };
 
     // Before dumping the module, we want all the TypeTrees to become part of the module.
     for item in diff_items.iter() {
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index adfe8aeb5c5..b4e9b9f44f4 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -126,6 +126,10 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         unsafe { llvm::LLVMGetUndef(t) }
     }
 
+    fn is_undef(&self, v: &'ll Value) -> bool {
+        unsafe { llvm::LLVMIsUndef(v) == True }
+    }
+
     fn const_poison(&self, t: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMGetPoison(t) }
     }
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 65345751842..79381f35a3c 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -1,11 +1,13 @@
 use std::borrow::Borrow;
 use std::cell::{Cell, RefCell};
 use std::ffi::{CStr, c_char, c_uint};
+use std::ops::Deref;
 use std::str;
 
 use rustc_abi::{HasDataLayout, TargetDataLayout, VariantIdx};
 use rustc_codegen_ssa::back::versioned_llvm_target;
 use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh};
+use rustc_codegen_ssa::common::TypeKind;
 use rustc_codegen_ssa::errors as ssa_errors;
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
@@ -30,23 +32,46 @@ use smallvec::SmallVec;
 
 use crate::back::write::to_llvm_code_model;
 use crate::callee::get_fn;
-use crate::common::AsCCharPtr;
+use crate::common::{self, AsCCharPtr};
 use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
 use crate::llvm::{Metadata, MetadataType};
 use crate::type_::Type;
 use crate::value::Value;
 use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util};
 
+/// `TyCtxt` (and related cache datastructures) can't be move between threads.
+/// However, there are various cx related functions which we want to be available to the builder and
+/// other compiler pieces. Here we define a small subset which has enough information and can be
+/// moved around more freely.
+pub(crate) struct SimpleCx<'ll> {
+    pub llmod: &'ll llvm::Module,
+    pub llcx: &'ll llvm::Context,
+}
+
+impl<'ll> Borrow<SimpleCx<'ll>> for CodegenCx<'ll, '_> {
+    fn borrow(&self) -> &SimpleCx<'ll> {
+        &self.scx
+    }
+}
+
+impl<'ll, 'tcx> Deref for CodegenCx<'ll, 'tcx> {
+    type Target = SimpleCx<'ll>;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        &self.scx
+    }
+}
+
 /// There is one `CodegenCx` per codegen unit. Each one has its own LLVM
 /// `llvm::Context` so that several codegen units may be processed in parallel.
 /// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`.
 pub(crate) struct CodegenCx<'ll, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
+    pub scx: SimpleCx<'ll>,
     pub use_dll_storage_attrs: bool,
     pub tls_model: llvm::ThreadLocalMode,
 
-    pub llmod: &'ll llvm::Module,
-    pub llcx: &'ll llvm::Context,
     pub codegen_unit: &'tcx CodegenUnit<'tcx>,
 
     /// Cache instances of monomorphic and polymorphic items
@@ -553,10 +578,9 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
 
         CodegenCx {
             tcx,
+            scx: SimpleCx { llcx, llmod },
             use_dll_storage_attrs,
             tls_model,
-            llmod,
-            llcx,
             codegen_unit,
             instances: Default::default(),
             vtables: Default::default(),
@@ -600,6 +624,11 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             llvm::set_section(g, c"llvm.metadata");
         }
     }
+}
+impl<'ll> SimpleCx<'ll> {
+    pub(crate) fn val_ty(&self, v: &'ll Value) -> &'ll Type {
+        common::val_ty(v)
+    }
 
     pub(crate) fn get_metadata_value(&self, metadata: &'ll Metadata) -> &'ll Value {
         unsafe { llvm::LLVMMetadataAsValue(self.llcx, metadata) }
@@ -625,6 +654,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             llvm::LLVMMDStringInContext2(self.llcx, name.as_ptr() as *const c_char, name.len())
         })
     }
+
+    pub(crate) fn type_kind(&self, ty: &'ll Type) -> TypeKind {
+        unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() }
+    }
 }
 
 impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
@@ -751,7 +784,6 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         } else {
             // If the symbol already exists, it is an error: for example, the user wrote
             // #[no_mangle] extern "C" fn main(..) {..}
-            // instead of #[start]
             None
         }
     }
@@ -1179,6 +1211,20 @@ impl CodegenCx<'_, '_> {
     }
 }
 
+// This is a duplication of the set_metadata function above. However, so far it's the only one
+// shared between both contexts, so it doesn't seem worth it to make the Cx generic like we did it
+// for the Builder.
+impl SimpleCx<'_> {
+    #[allow(unused)]
+    /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`.
+    pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) {
+        unsafe {
+            let node = llvm::LLVMMetadataAsValue(&self.llcx, md);
+            llvm::LLVMSetMetadata(val, kind_id as c_uint, node);
+        }
+    }
+}
+
 impl HasDataLayout for CodegenCx<'_, '_> {
     #[inline]
     fn data_layout(&self) -> &TargetDataLayout {
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index b3ad2a0e409..fd22421c7fc 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -9,6 +9,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::IndexVec;
 use rustc_middle::mir;
+use rustc_middle::mir::mono::MonoItemPartitions;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::RemapFileNameExt;
 use rustc_session::config::RemapPathScopeComponents;
@@ -297,12 +298,13 @@ struct UsageSets<'tcx> {
 /// Prepare sets of definitions that are relevant to deciding whether something
 /// is an "unused function" for coverage purposes.
 fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> {
-    let (all_mono_items, cgus) = tcx.collect_and_partition_mono_items(());
+    let MonoItemPartitions { all_mono_items, codegen_units } =
+        tcx.collect_and_partition_mono_items(());
 
     // Obtain a MIR body for each function participating in codegen, via an
     // arbitrary instance.
     let mut def_ids_seen = FxHashSet::default();
-    let def_and_mir_for_all_mono_fns = cgus
+    let def_and_mir_for_all_mono_fns = codegen_units
         .iter()
         .flat_map(|cgu| cgu.items().keys())
         .filter_map(|item| match item {
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
index 5428d776f41..460a4664615 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
@@ -51,7 +51,7 @@ pub(crate) fn prepare_covfun_record<'tcx>(
     is_used: bool,
 ) -> Option<CovfunRecord<'tcx>> {
     let fn_cov_info = tcx.instance_mir(instance.def).function_coverage_info.as_deref()?;
-    let ids_info = tcx.coverage_ids_info(instance.def);
+    let ids_info = tcx.coverage_ids_info(instance.def)?;
 
     let expressions = prepare_expressions(fn_cov_info, ids_info, is_used);
 
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 7311cd9d230..021108cd51c 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -8,7 +8,6 @@ use rustc_codegen_ssa::traits::{
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::ty::Instance;
-use rustc_middle::ty::layout::HasTyCtxt;
 use tracing::{debug, instrument};
 
 use crate::builder::Builder;
@@ -147,6 +146,10 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
             debug!("function has a coverage statement but no coverage info");
             return;
         };
+        let Some(ids_info) = bx.tcx.coverage_ids_info(instance.def) else {
+            debug!("function has a coverage statement but no IDs info");
+            return;
+        };
 
         // Mark the instance as used in this CGU, for coverage purposes.
         // This includes functions that were not partitioned into this CGU,
@@ -162,8 +165,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
                 // be smaller than the number originally inserted by the instrumentor,
                 // if some high-numbered counters were removed by MIR optimizations.
                 // If so, LLVM's profiler runtime will use fewer physical counters.
-                let num_counters =
-                    bx.tcx().coverage_ids_info(instance.def).num_counters_after_mir_opts();
+                let num_counters = ids_info.num_counters_after_mir_opts();
                 assert!(
                     num_counters as usize <= function_coverage_info.num_counters,
                     "num_counters disagreement: query says {num_counters} but function info only has {}",
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index e545ce386ed..11eb9651af6 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -9,7 +9,7 @@ use rustc_middle::mir::{Body, SourceScope};
 use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
 use rustc_middle::ty::{self, Instance};
 use rustc_session::config::DebugInfo;
-use rustc_span::{BytePos, hygiene};
+use rustc_span::{BytePos, DUMMY_SP, hygiene};
 
 use super::metadata::file_metadata;
 use super::utils::DIB;
@@ -85,23 +85,15 @@ fn make_mir_scope<'ll, 'tcx>(
             discriminators,
             parent,
         );
-        if let Some(parent_scope) = debug_context.scopes[parent] {
-            parent_scope
-        } else {
-            // If the parent scope could not be represented then no children
-            // can be either.
-            debug_context.scopes[scope] = None;
-            instantiated.insert(scope);
-            return;
-        }
+        debug_context.scopes[parent]
     } else {
         // The root is the function itself.
         let file = cx.sess().source_map().lookup_source_file(mir.span.lo());
-        debug_context.scopes[scope] = Some(DebugScope {
+        debug_context.scopes[scope] = DebugScope {
             file_start_pos: file.start_pos,
             file_end_pos: file.end_position(),
-            ..debug_context.scopes[scope].unwrap()
-        });
+            ..debug_context.scopes[scope]
+        };
         instantiated.insert(scope);
         return;
     };
@@ -112,7 +104,7 @@ fn make_mir_scope<'ll, 'tcx>(
     {
         // Do not create a DIScope if there are no variables defined in this
         // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
-        debug_context.scopes[scope] = Some(parent_scope);
+        debug_context.scopes[scope] = parent_scope;
         instantiated.insert(scope);
         return;
     }
@@ -145,14 +137,7 @@ fn make_mir_scope<'ll, 'tcx>(
         },
     };
 
-    let mut debug_scope = Some(DebugScope {
-        dbg_scope,
-        inlined_at: parent_scope.inlined_at,
-        file_start_pos: loc.file.start_pos,
-        file_end_pos: loc.file.end_position(),
-    });
-
-    if let Some((_, callsite_span)) = scope_data.inlined {
+    let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
         let callsite_span = hygiene::walk_chain_collapsed(callsite_span, mir.span);
         let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
         let loc = cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span);
@@ -175,29 +160,29 @@ fn make_mir_scope<'ll, 'tcx>(
         // Note further that we can't key this hashtable on the span itself,
         // because these spans could have distinct SyntaxContexts. We have
         // to key on exactly what we're giving to LLVM.
-        let inlined_at = match discriminators.entry(callsite_span.lo()) {
+        match discriminators.entry(callsite_span.lo()) {
             Entry::Occupied(mut o) => {
                 *o.get_mut() += 1;
+                // NB: We have to emit *something* here or we'll fail LLVM IR verification
+                // in at least some circumstances (see issue #135322) so if the required
+                // discriminant cannot be encoded fall back to the dummy location.
                 unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, *o.get()) }
+                    .unwrap_or_else(|| {
+                        cx.dbg_loc(callsite_scope, parent_scope.inlined_at, DUMMY_SP)
+                    })
             }
             Entry::Vacant(v) => {
                 v.insert(0);
-                Some(loc)
-            }
-        };
-        match inlined_at {
-            Some(inlined_at) => {
-                debug_scope.as_mut().unwrap().inlined_at = Some(inlined_at);
-            }
-            None => {
-                // LLVM has a maximum discriminator that it can encode (currently
-                // it uses 12 bits for 4096 possible values). If we exceed that
-                // there is little we can do but drop the debug info.
-                debug_scope = None;
+                loc
             }
         }
-    }
+    });
 
-    debug_context.scopes[scope] = debug_scope;
+    debug_context.scopes[scope] = DebugScope {
+        dbg_scope,
+        inlined_at: inlined_at.or(parent_scope.inlined_at),
+        file_start_pos: loc.file.start_pos,
+        file_end_pos: loc.file.end_position(),
+    };
     instantiated.insert(scope);
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 88e43e1c678..8d782a618fc 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -442,7 +442,7 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) ->
         // (or if there is no allocator argument).
         ty::Adt(def, args)
             if def.is_box()
-                && args.get(1).map_or(true, |arg| cx.layout_of(arg.expect_ty()).is_1zst()) =>
+                && args.get(1).is_none_or(|arg| cx.layout_of(arg.expect_ty()).is_1zst()) =>
         {
             build_pointer_or_reference_di_node(cx, t, t.expect_boxed_ty(), unique_type_id)
         }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 755f4816acf..e6778411365 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -295,12 +295,12 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         }
 
         // Initialize fn debug context (including scopes).
-        let empty_scope = Some(DebugScope {
+        let empty_scope = DebugScope {
             dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
             inlined_at: None,
             file_start_pos: BytePos(0),
             file_end_pos: BytePos(0),
-        });
+        };
         let mut fn_debug_context = FunctionDebugContext {
             scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes),
             inlined_function_scopes: Default::default(),
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index c72b5b5611f..bdc83267cca 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -21,26 +21,26 @@ use tracing::debug;
 
 use crate::abi::{FnAbi, FnAbiLlvmExt};
 use crate::common::AsCCharPtr;
-use crate::context::CodegenCx;
+use crate::context::{CodegenCx, SimpleCx};
 use crate::llvm::AttributePlace::Function;
 use crate::llvm::Visibility;
 use crate::type_::Type;
 use crate::value::Value;
 use crate::{attributes, llvm};
 
-/// Declare a function.
+/// Declare a function with a SimpleCx.
 ///
 /// If there’s a value with the same name already declared, the function will
 /// update the declaration and return existing Value instead.
-pub(crate) fn declare_raw_fn<'ll>(
-    cx: &CodegenCx<'ll, '_>,
+pub(crate) fn declare_simple_fn<'ll>(
+    cx: &SimpleCx<'ll>,
     name: &str,
     callconv: llvm::CallConv,
     unnamed: llvm::UnnamedAddr,
     visibility: llvm::Visibility,
     ty: &'ll Type,
 ) -> &'ll Value {
-    debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
+    debug!("declare_simple_fn(name={:?}, ty={:?})", name, ty);
     let llfn = unsafe {
         llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_c_char_ptr(), name.len(), ty)
     };
@@ -49,6 +49,24 @@ pub(crate) fn declare_raw_fn<'ll>(
     llvm::SetUnnamedAddress(llfn, unnamed);
     llvm::set_visibility(llfn, visibility);
 
+    llfn
+}
+
+/// Declare a function.
+///
+/// If there’s a value with the same name already declared, the function will
+/// update the declaration and return existing Value instead.
+pub(crate) fn declare_raw_fn<'ll, 'tcx>(
+    cx: &CodegenCx<'ll, 'tcx>,
+    name: &str,
+    callconv: llvm::CallConv,
+    unnamed: llvm::UnnamedAddr,
+    visibility: llvm::Visibility,
+    ty: &'ll Type,
+) -> &'ll Value {
+    debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
+    let llfn = declare_simple_fn(cx, name, callconv, unnamed, visibility, ty);
+
     let mut attrs = SmallVec::<[_; 4]>::new();
 
     if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.disable_redzone) {
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index cabcfc9b42b..eab4a9f30c9 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1081,11 +1081,11 @@ fn codegen_emcc_try<'ll>(
 
 // Helper function to give a Block to a closure to codegen a shim function.
 // This is currently primarily used for the `try` intrinsic functions above.
-fn gen_fn<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
+fn gen_fn<'a, 'll, 'tcx>(
+    cx: &'a CodegenCx<'ll, 'tcx>,
     name: &str,
     rust_fn_sig: ty::PolyFnSig<'tcx>,
-    codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
+    codegen: &mut dyn FnMut(Builder<'a, 'll, 'tcx>),
 ) -> (&'ll Type, &'ll Value) {
     let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
     let llty = fn_abi.llvm_type(cx);
@@ -1104,9 +1104,9 @@ fn gen_fn<'ll, 'tcx>(
 // catch exceptions.
 //
 // This function is only generated once and is then cached.
-fn get_rust_try_fn<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
-    codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
+fn get_rust_try_fn<'a, 'll, 'tcx>(
+    cx: &'a CodegenCx<'ll, 'tcx>,
+    codegen: &mut dyn FnMut(Builder<'a, 'll, 'tcx>),
 ) -> (&'ll Type, &'ll Value) {
     if let Some(llfn) = cx.rust_try_fn.get() {
         return llfn;
@@ -1182,6 +1182,60 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         }};
     }
 
+    /// Returns the bitwidth of the `$ty` argument if it is an `Int` type.
+    macro_rules! require_int_ty {
+        ($ty: expr, $diag: expr) => {
+            match $ty {
+                ty::Int(i) => i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
+                _ => {
+                    return_error!($diag);
+                }
+            }
+        };
+    }
+
+    /// Returns the bitwidth of the `$ty` argument if it is an `Int` or `Uint` type.
+    macro_rules! require_int_or_uint_ty {
+        ($ty: expr, $diag: expr) => {
+            match $ty {
+                ty::Int(i) => i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
+                ty::Uint(i) => {
+                    i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits())
+                }
+                _ => {
+                    return_error!($diag);
+                }
+            }
+        };
+    }
+
+    /// Converts a vector mask, where each element has a bit width equal to the data elements it is used with,
+    /// down to an i1 based mask that can be used by llvm intrinsics.
+    ///
+    /// The rust simd semantics are that each element should either consist of all ones or all zeroes,
+    /// but this information is not available to llvm. Truncating the vector effectively uses the lowest bit,
+    /// but codegen for several targets is better if we consider the highest bit by shifting.
+    ///
+    /// For x86 SSE/AVX targets this is beneficial since most instructions with mask parameters only consider the highest bit.
+    /// So even though on llvm level we have an additional shift, in the final assembly there is no shift or truncate and
+    /// instead the mask can be used as is.
+    ///
+    /// For aarch64 and other targets there is a benefit because a mask from the sign bit can be more
+    /// efficiently converted to an all ones / all zeroes mask by comparing whether each element is negative.
+    fn vector_mask_to_bitmask<'a, 'll, 'tcx>(
+        bx: &mut Builder<'a, 'll, 'tcx>,
+        i_xn: &'ll Value,
+        in_elem_bitwidth: u64,
+        in_len: u64,
+    ) -> &'ll Value {
+        // Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position.
+        let shift_idx = bx.cx.const_int(bx.type_ix(in_elem_bitwidth), (in_elem_bitwidth - 1) as _);
+        let shift_indices = vec![shift_idx; in_len as _];
+        let i_xn_msb = bx.lshr(i_xn, bx.const_vector(shift_indices.as_slice()));
+        // Truncate vector to an <i1 x N>
+        bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len))
+    }
+
     let tcx = bx.tcx();
     let sig = tcx.normalize_erasing_late_bound_regions(bx.typing_env(), callee_ty.fn_sig(tcx));
     let arg_tys = sig.inputs();
@@ -1433,14 +1487,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             m_len,
             v_len
         });
-        match m_elem_ty.kind() {
-            ty::Int(_) => {}
-            _ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }),
-        }
-        // truncate the mask to a vector of i1s
-        let i1 = bx.type_i1();
-        let i1xn = bx.type_vector(i1, m_len as u64);
-        let m_i1s = bx.trunc(args[0].immediate(), i1xn);
+        let in_elem_bitwidth =
+            require_int_ty!(m_elem_ty.kind(), InvalidMonomorphization::MaskType {
+                span,
+                name,
+                ty: m_elem_ty
+            });
+        let m_i1s = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len);
         return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
     }
 
@@ -1457,33 +1510,15 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         let expected_bytes = in_len.div_ceil(8);
 
         // Integer vector <i{in_bitwidth} x in_len>:
-        let (i_xn, in_elem_bitwidth) = match in_elem.kind() {
-            ty::Int(i) => (
-                args[0].immediate(),
-                i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
-            ),
-            ty::Uint(i) => (
-                args[0].immediate(),
-                i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
-            ),
-            _ => return_error!(InvalidMonomorphization::VectorArgument {
+        let in_elem_bitwidth =
+            require_int_or_uint_ty!(in_elem.kind(), InvalidMonomorphization::VectorArgument {
                 span,
                 name,
                 in_ty,
                 in_elem
-            }),
-        };
+            });
 
-        // LLVM doesn't always know the inputs are `0` or `!0`, so we shift here so it optimizes to
-        // `pmovmskb` and similar on x86.
-        let shift_indices =
-            vec![
-                bx.cx.const_int(bx.type_ix(in_elem_bitwidth), (in_elem_bitwidth - 1) as _);
-                in_len as _
-            ];
-        let i_xn_msb = bx.lshr(i_xn, bx.const_vector(shift_indices.as_slice()));
-        // Truncate vector to an <i1 x N>
-        let i1xn = bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len));
+        let i1xn = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, in_len);
         // Bitcast <i1 x N> to iN:
         let i_ = bx.bitcast(i1xn, bx.type_ix(in_len));
 
@@ -1704,28 +1739,21 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             }
         );
 
-        match element_ty2.kind() {
-            ty::Int(_) => (),
-            _ => {
-                return_error!(InvalidMonomorphization::ThirdArgElementType {
-                    span,
-                    name,
-                    expected_element: element_ty2,
-                    third_arg: arg_tys[2]
-                });
-            }
-        }
+        let mask_elem_bitwidth =
+            require_int_ty!(element_ty2.kind(), InvalidMonomorphization::ThirdArgElementType {
+                span,
+                name,
+                expected_element: element_ty2,
+                third_arg: arg_tys[2]
+            });
 
         // Alignment of T, must be a constant integer value:
         let alignment_ty = bx.type_i32();
         let alignment = bx.const_i32(bx.align_of(in_elem).bytes() as i32);
 
         // Truncate the mask vector to a vector of i1s:
-        let (mask, mask_ty) = {
-            let i1 = bx.type_i1();
-            let i1xn = bx.type_vector(i1, in_len);
-            (bx.trunc(args[2].immediate(), i1xn), i1xn)
-        };
+        let mask = vector_mask_to_bitmask(bx, args[2].immediate(), mask_elem_bitwidth, in_len);
+        let mask_ty = bx.type_vector(bx.type_i1(), in_len);
 
         // Type of the vector of pointers:
         let llvm_pointer_vec_ty = llvm_vector_ty(bx, element_ty1, in_len);
@@ -1810,27 +1838,21 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             }
         );
 
-        require!(
-            matches!(mask_elem.kind(), ty::Int(_)),
-            InvalidMonomorphization::ThirdArgElementType {
+        let m_elem_bitwidth =
+            require_int_ty!(mask_elem.kind(), InvalidMonomorphization::ThirdArgElementType {
                 span,
                 name,
                 expected_element: values_elem,
                 third_arg: mask_ty,
-            }
-        );
+            });
+
+        let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
+        let mask_ty = bx.type_vector(bx.type_i1(), mask_len);
 
         // Alignment of T, must be a constant integer value:
         let alignment_ty = bx.type_i32();
         let alignment = bx.const_i32(bx.align_of(values_elem).bytes() as i32);
 
-        // Truncate the mask vector to a vector of i1s:
-        let (mask, mask_ty) = {
-            let i1 = bx.type_i1();
-            let i1xn = bx.type_vector(i1, mask_len);
-            (bx.trunc(args[0].immediate(), i1xn), i1xn)
-        };
-
         let llvm_pointer = bx.type_ptr();
 
         // Type of the vector of elements:
@@ -1901,27 +1923,21 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             }
         );
 
-        require!(
-            matches!(mask_elem.kind(), ty::Int(_)),
-            InvalidMonomorphization::ThirdArgElementType {
+        let m_elem_bitwidth =
+            require_int_ty!(mask_elem.kind(), InvalidMonomorphization::ThirdArgElementType {
                 span,
                 name,
                 expected_element: values_elem,
                 third_arg: mask_ty,
-            }
-        );
+            });
+
+        let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
+        let mask_ty = bx.type_vector(bx.type_i1(), mask_len);
 
         // Alignment of T, must be a constant integer value:
         let alignment_ty = bx.type_i32();
         let alignment = bx.const_i32(bx.align_of(values_elem).bytes() as i32);
 
-        // Truncate the mask vector to a vector of i1s:
-        let (mask, mask_ty) = {
-            let i1 = bx.type_i1();
-            let i1xn = bx.type_vector(i1, in_len);
-            (bx.trunc(args[0].immediate(), i1xn), i1xn)
-        };
-
         let ret_t = bx.type_void();
 
         let llvm_pointer = bx.type_ptr();
@@ -1995,28 +2011,21 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         );
 
         // The element type of the third argument must be a signed integer type of any width:
-        match element_ty2.kind() {
-            ty::Int(_) => (),
-            _ => {
-                return_error!(InvalidMonomorphization::ThirdArgElementType {
-                    span,
-                    name,
-                    expected_element: element_ty2,
-                    third_arg: arg_tys[2]
-                });
-            }
-        }
+        let mask_elem_bitwidth =
+            require_int_ty!(element_ty2.kind(), InvalidMonomorphization::ThirdArgElementType {
+                span,
+                name,
+                expected_element: element_ty2,
+                third_arg: arg_tys[2]
+            });
 
         // Alignment of T, must be a constant integer value:
         let alignment_ty = bx.type_i32();
         let alignment = bx.const_i32(bx.align_of(in_elem).bytes() as i32);
 
         // Truncate the mask vector to a vector of i1s:
-        let (mask, mask_ty) = {
-            let i1 = bx.type_i1();
-            let i1xn = bx.type_vector(i1, in_len);
-            (bx.trunc(args[2].immediate(), i1xn), i1xn)
-        };
+        let mask = vector_mask_to_bitmask(bx, args[2].immediate(), mask_elem_bitwidth, in_len);
+        let mask_ty = bx.type_vector(bx.type_i1(), in_len);
 
         let ret_t = bx.type_void();
 
@@ -2164,8 +2173,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                     });
                     args[0].immediate()
                 } else {
-                    match in_elem.kind() {
-                        ty::Int(_) | ty::Uint(_) => {}
+                    let bitwidth = match in_elem.kind() {
+                        ty::Int(i) => {
+                            i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits())
+                        }
+                        ty::Uint(i) => {
+                            i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits())
+                        }
                         _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
                             span,
                             name,
@@ -2174,12 +2188,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                             in_elem,
                             ret_ty
                         }),
-                    }
+                    };
 
-                    // boolean reductions operate on vectors of i1s:
-                    let i1 = bx.type_i1();
-                    let i1xn = bx.type_vector(i1, in_len as u64);
-                    bx.trunc(args[0].immediate(), i1xn)
+                    vector_mask_to_bitmask(bx, args[0].immediate(), bitwidth, in_len as _)
                 };
                 return match in_elem.kind() {
                     ty::Int(_) | ty::Uint(_) => {
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 06afe8bb3ad..4a84fd29e44 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -237,7 +237,6 @@ impl WriteBackendMethods for LlvmCodegenBackend {
     /// Generate autodiff rules
     fn autodiff(
         cgcx: &CodegenContext<Self>,
-        tcx: TyCtxt<'_>,
         module: &ModuleCodegen<Self::Module>,
         diff_fncs: Vec<AutoDiffItem>,
         config: &ModuleConfig,
@@ -246,7 +245,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
             let dcx = cgcx.create_dcx();
             return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO));
         }
-        builder::autodiff::differentiate(module, cgcx, tcx, diff_fncs, config)
+        builder::autodiff::differentiate(module, cgcx, diff_fncs, config)
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index ec6c84f6f25..009d15a932f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -741,8 +741,11 @@ pub mod debuginfo {
     pub type DIEnumerator = DIDescriptor;
     pub type DITemplateTypeParameter = DIDescriptor;
 
-    // These values **must** match with LLVMRustDIFlags!!
     bitflags! {
+        /// Must match the layout of `LLVMDIFlags` in the LLVM-C API.
+        ///
+        /// Each value declared here must also be covered by the static
+        /// assertions in `RustWrapper.cpp` used by `fromRust(LLVMDIFlags)`.
         #[repr(transparent)]
         #[derive(Clone, Copy, Default)]
         pub struct DIFlags: u32 {
@@ -752,7 +755,7 @@ pub mod debuginfo {
             const FlagPublic              = 3;
             const FlagFwdDecl             = (1 << 2);
             const FlagAppleBlock          = (1 << 3);
-            const FlagBlockByrefStruct    = (1 << 4);
+            const FlagReservedBit4        = (1 << 4);
             const FlagVirtual             = (1 << 5);
             const FlagArtificial          = (1 << 6);
             const FlagExplicit            = (1 << 7);
@@ -763,10 +766,21 @@ pub mod debuginfo {
             const FlagStaticMember        = (1 << 12);
             const FlagLValueReference     = (1 << 13);
             const FlagRValueReference     = (1 << 14);
-            const FlagExternalTypeRef     = (1 << 15);
+            const FlagReserved            = (1 << 15);
+            const FlagSingleInheritance   = (1 << 16);
+            const FlagMultipleInheritance = (2 << 16);
+            const FlagVirtualInheritance  = (3 << 16);
             const FlagIntroducedVirtual   = (1 << 18);
             const FlagBitField            = (1 << 19);
             const FlagNoReturn            = (1 << 20);
+            // The bit at (1 << 21) is unused, but was `LLVMDIFlagMainSubprogram`.
+            const FlagTypePassByValue     = (1 << 22);
+            const FlagTypePassByReference = (1 << 23);
+            const FlagEnumClass           = (1 << 24);
+            const FlagThunk               = (1 << 25);
+            const FlagNonTrivial          = (1 << 26);
+            const FlagBigEndian           = (1 << 27);
+            const FlagLittleEndian        = (1 << 28);
         }
     }
 
@@ -918,6 +932,7 @@ unsafe extern "C" {
     pub fn LLVMMetadataTypeInContext(C: &Context) -> &Type;
 
     // Operations on all values
+    pub fn LLVMIsUndef(Val: &Value) -> Bool;
     pub fn LLVMTypeOf(Val: &Value) -> &Type;
     pub fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char;
     pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 6aec078e0de..c56ad886120 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::{self, Ty};
 use rustc_target::callconv::{CastTarget, FnAbi, Reg};
 
 use crate::abi::{FnAbiLlvmExt, LlvmType};
-use crate::context::CodegenCx;
+use crate::context::{CodegenCx, SimpleCx};
 pub(crate) use crate::llvm::Type;
 use crate::llvm::{Bool, False, Metadata, True};
 use crate::type_of::LayoutLlvmExt;
@@ -35,7 +35,8 @@ impl fmt::Debug for Type {
     }
 }
 
-impl<'ll> CodegenCx<'ll, '_> {
+impl<'ll> CodegenCx<'ll, '_> {}
+impl<'ll> SimpleCx<'ll> {
     pub(crate) fn type_named_struct(&self, name: &str) -> &'ll Type {
         let name = SmallCStr::new(name);
         unsafe { llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr()) }
@@ -44,11 +45,9 @@ impl<'ll> CodegenCx<'ll, '_> {
     pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) {
         unsafe { llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed as Bool) }
     }
-
     pub(crate) fn type_void(&self) -> &'ll Type {
         unsafe { llvm::LLVMVoidTypeInContext(self.llcx) }
     }
-
     pub(crate) fn type_token(&self) -> &'ll Type {
         unsafe { llvm::LLVMTokenTypeInContext(self.llcx) }
     }
@@ -75,7 +74,8 @@ impl<'ll> CodegenCx<'ll, '_> {
             args
         }
     }
-
+}
+impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
     pub(crate) fn type_bool(&self) -> &'ll Type {
         self.type_i8()
     }
@@ -120,7 +120,8 @@ impl<'ll> CodegenCx<'ll, '_> {
         assert_eq!(size % unit_size, 0);
         self.type_array(self.type_from_integer(unit), size / unit_size)
     }
-
+}
+impl<'ll> SimpleCx<'ll> {
     pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
         unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) }
     }
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 3254b5d38e7..b22357acdc2 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2021"
 ar_archive_writer = "0.4.2"
 arrayvec = { version = "0.7", default-features = false }
 bitflags = "2.4.1"
+bstr = "1.11.3"
 # Pinned so `cargo update` bumps don't cause breakage. Please also update the
 # `cc` in `rustc_llvm` if you update the `cc` here.
 cc = "=1.2.7"
@@ -59,5 +60,5 @@ default-features = false
 features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write", "wasm"]
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.57.0"
+version = "0.59.0"
 features = ["Win32_Globalization"]
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 484f467068a..de37de09f5a 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -183,6 +183,8 @@ codegen_ssa_linker_file_stem = couldn't extract file stem from specified linker
 codegen_ssa_linker_not_found = linker `{$linker_path}` not found
     .note = {$error}
 
+codegen_ssa_linker_output = {$inner}
+
 codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker
 
 codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
@@ -211,7 +213,7 @@ codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but
 codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
 
 codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times
-    .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
+    .help = did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point
 
 codegen_ssa_no_field = no field `{$name}`
 
diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
index ab65319e3d3..27331ce4ca6 100644
--- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
+++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
@@ -46,8 +46,12 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&mut CguReuseTr
             return;
         }
 
-        let available_cgus =
-            tcx.collect_and_partition_mono_items(()).1.iter().map(|cgu| cgu.name()).collect();
+        let available_cgus = tcx
+            .collect_and_partition_mono_items(())
+            .codegen_units
+            .iter()
+            .map(|cgu| cgu.name())
+            .collect();
 
         let mut ams = AssertModuleSource {
             tcx,
diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs
index b3c5b86ccf4..63023fdba20 100644
--- a/compiler/rustc_codegen_ssa/src/back/command.rs
+++ b/compiler/rustc_codegen_ssa/src/back/command.rs
@@ -13,6 +13,7 @@ pub(crate) struct Command {
     args: Vec<OsString>,
     env: Vec<(OsString, OsString)>,
     env_remove: Vec<OsString>,
+    env_clear: bool,
 }
 
 #[derive(Clone)]
@@ -36,7 +37,13 @@ impl Command {
     }
 
     fn _new(program: Program) -> Command {
-        Command { program, args: Vec::new(), env: Vec::new(), env_remove: Vec::new() }
+        Command {
+            program,
+            args: Vec::new(),
+            env: Vec::new(),
+            env_remove: Vec::new(),
+            env_clear: false,
+        }
     }
 
     pub(crate) fn arg<P: AsRef<OsStr>>(&mut self, arg: P) -> &mut Command {
@@ -79,6 +86,11 @@ impl Command {
         self
     }
 
+    pub(crate) fn env_clear(&mut self) -> &mut Command {
+        self.env_clear = true;
+        self
+    }
+
     fn _env_remove(&mut self, key: &OsStr) {
         self.env_remove.push(key.to_owned());
     }
@@ -106,6 +118,9 @@ impl Command {
         for k in &self.env_remove {
             ret.env_remove(k);
         }
+        if self.env_clear {
+            ret.env_clear();
+        }
         ret
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index df35b5e8426..105a4cb81f0 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -15,12 +15,14 @@ use rustc_ast::CRATE_NODE_ID;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::temp_dir::MaybeTempDir;
-use rustc_errors::DiagCtxtHandle;
+use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
 use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc_macros::LintDiagnostic;
 use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
 use rustc_metadata::{find_native_static_library, walk_native_lib_search_dirs};
 use rustc_middle::bug;
+use rustc_middle::lint::lint_level;
 use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
@@ -29,6 +31,7 @@ use rustc_session::config::{
     OutputType, PrintKind, SplitDwarfKind, Strip,
 };
 use rustc_session::cstore::DllImport;
+use rustc_session::lint::builtin::LINKER_MESSAGES;
 use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
 use rustc_session::search_paths::PathKind;
 use rustc_session::utils::NativeLibKind;
@@ -749,6 +752,14 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
     }
 }
 
+#[derive(LintDiagnostic)]
+#[diag(codegen_ssa_linker_output)]
+/// Translating this is kind of useless. We don't pass translation flags to the linker, so we'd just
+/// end up with inconsistent languages within the same diagnostic.
+struct LinkerOutput {
+    inner: String,
+}
+
 /// Create a dynamic library or executable.
 ///
 /// This will invoke the system linker/cc to create the resulting file. This links to all upstream
@@ -981,6 +992,11 @@ fn link_natively(
 
     match prog {
         Ok(prog) => {
+            let is_msvc_link_exe = sess.target.is_like_msvc
+                && flavor == LinkerFlavor::Msvc(Lld::No)
+                // Match exactly "link.exe"
+                && linker_path.to_str() == Some("link.exe");
+
             if !prog.status.success() {
                 let mut output = prog.stderr.clone();
                 output.extend_from_slice(&prog.stdout);
@@ -991,22 +1007,16 @@ fn link_natively(
                     command: cmd,
                     escaped_output,
                     verbose: sess.opts.verbose,
+                    sysroot_dir: sess.sysroot.clone(),
                 };
                 sess.dcx().emit_err(err);
                 // If MSVC's `link.exe` was expected but the return code
                 // is not a Microsoft LNK error then suggest a way to fix or
                 // install the Visual Studio build tools.
                 if let Some(code) = prog.status.code() {
-                    if sess.target.is_like_msvc
-                        && flavor == LinkerFlavor::Msvc(Lld::No)
-                        // Respect the command line override
-                        && sess.opts.cg.linker.is_none()
-                        // Match exactly "link.exe"
-                        && linker_path.to_str() == Some("link.exe")
-                        // All Microsoft `link.exe` linking error codes are
-                        // four digit numbers in the range 1000 to 9999 inclusive
-                        && (code < 1000 || code > 9999)
-                    {
+                    // All Microsoft `link.exe` linking ror codes are
+                    // four digit numbers in the range 1000 to 9999 inclusive
+                    if is_msvc_link_exe && (code < 1000 || code > 9999) {
                         let is_vs_installed = windows_registry::find_vs_version().is_ok();
                         let has_linker =
                             windows_registry::find_tool(&sess.target.arch, "link.exe").is_some();
@@ -1028,8 +1038,49 @@ fn link_natively(
 
                 sess.dcx().abort_if_errors();
             }
-            info!("linker stderr:\n{}", escape_string(&prog.stderr));
-            info!("linker stdout:\n{}", escape_string(&prog.stdout));
+
+            let stderr = escape_string(&prog.stderr);
+            let mut stdout = escape_string(&prog.stdout);
+            info!("linker stderr:\n{}", &stderr);
+            info!("linker stdout:\n{}", &stdout);
+
+            // Hide some progress messages from link.exe that we don't care about.
+            // See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146
+            if is_msvc_link_exe {
+                if let Ok(str) = str::from_utf8(&prog.stdout) {
+                    let mut output = String::with_capacity(str.len());
+                    for line in stdout.lines() {
+                        if line.starts_with("   Creating library")
+                            || line.starts_with("Generating code")
+                            || line.starts_with("Finished generating code")
+                        {
+                            continue;
+                        }
+                        output += line;
+                        output += "\r\n"
+                    }
+                    stdout = escape_string(output.trim().as_bytes())
+                }
+            }
+
+            let (level, src) = codegen_results.crate_info.lint_levels.linker_messages;
+            let lint = |msg| {
+                lint_level(sess, LINKER_MESSAGES, level, src, None, |diag| {
+                    LinkerOutput { inner: msg }.decorate_lint(diag)
+                })
+            };
+
+            if !prog.stderr.is_empty() {
+                // We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present.
+                let stderr = stderr
+                    .strip_prefix("warning: ")
+                    .unwrap_or(&stderr)
+                    .replace(": warning: ", ": ");
+                lint(format!("linker stderr: {stderr}"));
+            }
+            if !stdout.is_empty() {
+                lint(format!("linker stdout: {}", stdout))
+            }
         }
         Err(e) => {
             let linker_not_found = e.kind() == io::ErrorKind::NotFound;
diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs
index efccf7687a1..9fd984b6419 100644
--- a/compiler/rustc_codegen_ssa/src/back/lto.rs
+++ b/compiler/rustc_codegen_ssa/src/back/lto.rs
@@ -4,7 +4,6 @@ use std::sync::Arc;
 use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
 use rustc_data_structures::memmap::Mmap;
 use rustc_errors::FatalError;
-use rustc_middle::ty::TyCtxt;
 
 use super::write::CodegenContext;
 use crate::ModuleCodegen;
@@ -89,13 +88,12 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
     pub unsafe fn autodiff(
         self,
         cgcx: &CodegenContext<B>,
-        tcx: TyCtxt<'_>,
         diff_fncs: Vec<AutoDiffItem>,
         config: &ModuleConfig,
     ) -> Result<LtoModuleCodegen<B>, FatalError> {
         match &self {
             LtoModuleCodegen::Fat(module) => {
-                B::autodiff(cgcx, tcx, &module, diff_fncs, config)?;
+                B::autodiff(cgcx, &module, diff_fncs, config)?;
             }
             _ => panic!("autodiff called with non-fat LTO module"),
         }
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 60ab2919352..f8f7bb2dbc6 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -293,7 +293,7 @@ fn exported_symbols_provider_local(
         // external linkage is enough for monomorphization to be linked to.
         let need_visibility = tcx.sess.target.dynamic_linking && !tcx.sess.target.only_cdylib;
 
-        let (_, cgus) = tcx.collect_and_partition_mono_items(());
+        let cgus = tcx.collect_and_partition_mono_items(()).codegen_units;
 
         // The symbols created in this loop are sorted below it
         #[allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 544578b29f1..e438bd70c51 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -44,7 +44,8 @@ use crate::mir::operand::OperandValue;
 use crate::mir::place::PlaceRef;
 use crate::traits::*;
 use crate::{
-    CachedModuleCodegen, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, errors, meth, mir,
+    CachedModuleCodegen, CodegenLintLevels, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
+    errors, meth, mir,
 };
 
 pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate {
@@ -490,8 +491,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         let ptr_ty = cx.type_ptr();
         let (arg_argc, arg_argv) = get_argc_argv(&mut bx);
 
-        let (start_fn, start_ty, args, instance) = if let EntryFnType::Main { sigpipe } = entry_type
-        {
+        let EntryFnType::Main { sigpipe } = entry_type;
+        let (start_fn, start_ty, args, instance) = {
             let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
             let start_instance = ty::Instance::expect_resolve(
                 cx.tcx(),
@@ -512,10 +513,6 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 vec![rust_main, arg_argc, arg_argv, arg_sigpipe],
                 Some(start_instance),
             )
-        } else {
-            debug!("using user-defined start fn");
-            let start_ty = cx.type_func(&[isize_ty, ptr_ty], isize_ty);
-            (rust_main, start_ty, vec![arg_argc, arg_argv], None)
         };
 
         let result = bx.call(start_ty, None, None, start_fn, &args, None, instance);
@@ -530,7 +527,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     }
 }
 
-/// Obtain the `argc` and `argv` values to pass to the rust start function.
+/// Obtain the `argc` and `argv` values to pass to the rust start function
+/// (i.e., the "start" lang item).
 fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &mut Bx) -> (Bx::Value, Bx::Value) {
     if bx.cx().sess().target.os.contains("uefi") {
         // Params for UEFI
@@ -621,7 +619,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
 
     // Run the monomorphization collector and partition the collected items into
     // codegen units.
-    let codegen_units = tcx.collect_and_partition_mono_items(()).1;
+    let codegen_units = tcx.collect_and_partition_mono_items(()).codegen_units;
 
     // Force all codegen_unit queries so they are already either red or green
     // when compile_codegen_unit accesses them. We are not able to re-execute
@@ -927,6 +925,7 @@ impl CrateInfo {
             dependency_formats: Lrc::clone(tcx.dependency_formats(())),
             windows_subsystem,
             natvis_debugger_visualizers: Default::default(),
+            lint_levels: CodegenLintLevels::from_tcx(tcx),
         };
 
         info.native_libraries.reserve(n_crates);
@@ -1052,14 +1051,11 @@ pub(crate) fn provide(providers: &mut Providers) {
             config::OptLevel::SizeMin => config::OptLevel::Default,
         };
 
-        let (defids, _) = tcx.collect_and_partition_mono_items(cratenum);
+        let defids = tcx.collect_and_partition_mono_items(cratenum).all_mono_items;
 
         let any_for_speed = defids.items().any(|id| {
             let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id);
-            match optimize {
-                attr::OptimizeAttr::None | attr::OptimizeAttr::Size => false,
-                attr::OptimizeAttr::Speed => true,
-            }
+            matches!(optimize, attr::OptimizeAttr::Speed)
         });
 
         if any_for_speed {
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 1daa17fbaf3..a0bc2d4ea48 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -575,7 +575,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         codegen_fn_attrs.inline = InlineAttr::Never;
     }
 
-    codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
+    codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::Default, |ia, attr| {
         if !attr.has_name(sym::optimize) {
             return ia;
         }
@@ -587,17 +587,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             inline_span = Some(attr.span);
             if items.len() != 1 {
                 err(attr.span, "expected one argument");
-                OptimizeAttr::None
+                OptimizeAttr::Default
             } else if list_contains_name(items, sym::size) {
                 OptimizeAttr::Size
             } else if list_contains_name(items, sym::speed) {
                 OptimizeAttr::Speed
+            } else if list_contains_name(items, sym::none) {
+                OptimizeAttr::DoNotOptimize
             } else {
                 err(items[0].span(), "invalid argument");
-                OptimizeAttr::None
+                OptimizeAttr::Default
             }
         } else {
-            OptimizeAttr::None
+            OptimizeAttr::Default
         }
     });
 
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index c7213bbc801..5e684632fb2 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -351,6 +351,7 @@ pub(crate) struct LinkingFailed<'a> {
     pub command: Command,
     pub escaped_output: String,
     pub verbose: bool,
+    pub sysroot_dir: PathBuf,
 }
 
 impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
@@ -364,6 +365,8 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
         if self.verbose {
             diag.note(format!("{:?}", self.command));
         } else {
+            self.command.env_clear();
+
             enum ArgGroup {
                 Regular(OsString),
                 Objects(usize),
@@ -398,26 +401,55 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
                     args.push(ArgGroup::Regular(arg));
                 }
             }
-            self.command.args(args.into_iter().map(|arg_group| match arg_group {
-                ArgGroup::Regular(arg) => arg,
-                ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")),
-                ArgGroup::Rlibs(dir, rlibs) => {
-                    let mut arg = dir.into_os_string();
-                    arg.push("/{");
-                    let mut first = true;
-                    for rlib in rlibs {
-                        if !first {
-                            arg.push(",");
+            let crate_hash = regex::bytes::Regex::new(r"-[0-9a-f]+\.rlib$").unwrap();
+            self.command.args(args.into_iter().map(|arg_group| {
+                match arg_group {
+                    // SAFETY: we are only matching on ASCII, not any surrogate pairs, so any replacements we do will still be valid.
+                    ArgGroup::Regular(arg) => unsafe {
+                        use bstr::ByteSlice;
+                        OsString::from_encoded_bytes_unchecked(
+                            arg.as_encoded_bytes().replace(
+                                self.sysroot_dir.as_os_str().as_encoded_bytes(),
+                                b"<sysroot>",
+                            ),
+                        )
+                    },
+                    ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")),
+                    ArgGroup::Rlibs(mut dir, rlibs) => {
+                        let is_sysroot_dir = match dir.strip_prefix(&self.sysroot_dir) {
+                            Ok(short) => {
+                                dir = Path::new("<sysroot>").join(short);
+                                true
+                            }
+                            Err(_) => false,
+                        };
+                        let mut arg = dir.into_os_string();
+                        arg.push("/{");
+                        let mut first = true;
+                        for mut rlib in rlibs {
+                            if !first {
+                                arg.push(",");
+                            }
+                            first = false;
+                            if is_sysroot_dir {
+                                // SAFETY: Regex works one byte at a type, and our regex will not match surrogate pairs (because it only matches ascii).
+                                rlib = unsafe {
+                                    OsString::from_encoded_bytes_unchecked(
+                                        crate_hash
+                                            .replace(rlib.as_encoded_bytes(), b"-*")
+                                            .into_owned(),
+                                    )
+                                };
+                            }
+                            arg.push(rlib);
                         }
-                        first = false;
-                        arg.push(rlib);
+                        arg.push("}.rlib");
+                        arg
                     }
-                    arg.push("}");
-                    arg
                 }
             }));
 
-            diag.note(format!("{:?}", self.command));
+            diag.note(format!("{:?}", self.command).trim_start_matches("env -i").to_owned());
             diag.note("some arguments are omitted. use `--verbose` to show all linker arguments");
         }
 
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 65c6067c740..40299ae2630 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -29,18 +29,23 @@ use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::unord::UnordMap;
+use rustc_hir::CRATE_HIR_ID;
 use rustc_hir::def_id::CrateNum;
 use rustc_macros::{Decodable, Encodable, HashStable};
 use rustc_middle::dep_graph::WorkProduct;
+use rustc_middle::lint::LintLevelSource;
 use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::dependency_format::Dependencies;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
+use rustc_middle::ty::TyCtxt;
 use rustc_middle::util::Providers;
 use rustc_serialize::opaque::{FileEncoder, MemDecoder};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_session::Session;
 use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
 use rustc_session::cstore::{self, CrateSource};
+use rustc_session::lint::Level;
+use rustc_session::lint::builtin::LINKER_MESSAGES;
 use rustc_session::utils::NativeLibKind;
 use rustc_span::Symbol;
 
@@ -200,6 +205,7 @@ pub struct CrateInfo {
     pub dependency_formats: Lrc<Dependencies>,
     pub windows_subsystem: Option<String>,
     pub natvis_debugger_visualizers: BTreeSet<DebuggerVisualizerFile>,
+    pub lint_levels: CodegenLintLevels,
 }
 
 #[derive(Encodable, Decodable)]
@@ -302,3 +308,19 @@ impl CodegenResults {
         Ok((codegen_results, outputs))
     }
 }
+
+/// A list of lint levels used in codegen.
+///
+/// When using `-Z link-only`, we don't have access to the tcx and must work
+/// solely from the `.rlink` file. `Lint`s are defined too early to be encodeable.
+/// Instead, encode exactly the information we need.
+#[derive(Copy, Clone, Debug, Encodable, Decodable)]
+pub struct CodegenLintLevels {
+    linker_messages: (Level, LintLevelSource),
+}
+
+impl CodegenLintLevels {
+    pub fn from_tcx(tcx: TyCtxt<'_>) -> Self {
+        Self { linker_messages: tcx.lint_level_at_node(LINKER_MESSAGES, CRATE_HIR_ID) }
+    }
+}
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 843a996d2bf..5924c8991ad 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -19,9 +19,7 @@ use crate::traits::*;
 
 pub struct FunctionDebugContext<'tcx, S, L> {
     /// Maps from source code to the corresponding debug info scope.
-    /// May be None if the backend is not capable of representing the scope for
-    /// some reason.
-    pub scopes: IndexVec<mir::SourceScope, Option<DebugScope<S, L>>>,
+    pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
 
     /// Maps from an inlined function to its debug info declaration.
     pub inlined_function_scopes: FxHashMap<Instance<'tcx>, S>,
@@ -232,7 +230,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         &self,
         source_info: mir::SourceInfo,
     ) -> Option<(Bx::DIScope, Option<Bx::DILocation>, Span)> {
-        let scope = &self.debug_context.as_ref()?.scopes[source_info.scope]?;
+        let scope = &self.debug_context.as_ref()?.scopes[source_info.scope];
         let span = hygiene::walk_chain_collapsed(source_info.span, self.mir.span);
         Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span))
     }
diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
index 8df270abc81..dc406809874 100644
--- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
@@ -1,10 +1,14 @@
+use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind};
 use rustc_attr_parsing::InstructionSetAttr;
+use rustc_hir::def_id::DefId;
 use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility};
 use rustc_middle::mir::{Body, InlineAsmOperand};
-use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf};
-use rustc_middle::ty::{Instance, TyCtxt};
-use rustc_middle::{bug, ty};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf};
+use rustc_middle::ty::{Instance, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug, ty};
 use rustc_span::sym;
+use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
+use rustc_target::spec::WasmCAbi;
 
 use crate::common;
 use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods};
@@ -32,7 +36,8 @@ pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     let item_data = cx.codegen_unit().items().get(&MonoItem::Fn(instance)).unwrap();
     let name = cx.mangled_name(instance);
-    let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data);
+    let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
+    let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data, fn_abi);
 
     let mut template_vec = Vec::new();
     template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin.into()));
@@ -103,6 +108,7 @@ enum AsmBinaryFormat {
     Elf,
     Macho,
     Coff,
+    Wasm,
 }
 
 impl AsmBinaryFormat {
@@ -111,6 +117,8 @@ impl AsmBinaryFormat {
             Self::Coff
         } else if target.is_like_osx {
             Self::Macho
+        } else if target.is_like_wasm {
+            Self::Wasm
         } else {
             Self::Elf
         }
@@ -122,6 +130,7 @@ fn prefix_and_suffix<'tcx>(
     instance: Instance<'tcx>,
     asm_name: &str,
     item_data: &MonoItemData,
+    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
 ) -> (String, String) {
     use std::fmt::Write;
 
@@ -169,7 +178,7 @@ fn prefix_and_suffix<'tcx>(
             }
             Linkage::LinkOnceAny | Linkage::LinkOnceODR | Linkage::WeakAny | Linkage::WeakODR => {
                 match asm_binary_format {
-                    AsmBinaryFormat::Elf | AsmBinaryFormat::Coff => {
+                    AsmBinaryFormat::Elf | AsmBinaryFormat::Coff | AsmBinaryFormat::Wasm => {
                         writeln!(w, ".weak {asm_name}")?;
                     }
                     AsmBinaryFormat::Macho => {
@@ -264,7 +273,161 @@ fn prefix_and_suffix<'tcx>(
                 writeln!(end, "{}", arch_suffix).unwrap();
             }
         }
+        AsmBinaryFormat::Wasm => {
+            let section = link_section.unwrap_or(format!(".text.{asm_name}"));
+
+            writeln!(begin, ".section {section},\"\",@").unwrap();
+            // wasm functions cannot be aligned, so skip
+            write_linkage(&mut begin).unwrap();
+            if let Visibility::Hidden = item_data.visibility {
+                writeln!(begin, ".hidden {asm_name}").unwrap();
+            }
+            writeln!(begin, ".type {asm_name}, @function").unwrap();
+            if !arch_prefix.is_empty() {
+                writeln!(begin, "{}", arch_prefix).unwrap();
+            }
+            writeln!(begin, "{asm_name}:").unwrap();
+            writeln!(
+                begin,
+                ".functype {asm_name} {}",
+                wasm_functype(tcx, fn_abi, instance.def_id())
+            )
+            .unwrap();
+
+            writeln!(end).unwrap();
+            // .size is ignored for function symbols, so we can skip it
+            writeln!(end, "end_function").unwrap();
+        }
     }
 
     (begin, end)
 }
+
+/// The webassembly type signature for the given function.
+///
+/// Used by the `.functype` directive on wasm targets.
+fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id: DefId) -> String {
+    let mut signature = String::with_capacity(64);
+
+    let ptr_type = match tcx.data_layout.pointer_size.bits() {
+        32 => "i32",
+        64 => "i64",
+        other => bug!("wasm pointer size cannot be {other} bits"),
+    };
+
+    // FIXME: remove this once the wasm32-unknown-unknown ABI is fixed
+    // please also add `wasm32-unknown-unknown` back in `tests/assembly/wasm32-naked-fn.rs`
+    // basically the commit introducing this comment should be reverted
+    if let PassMode::Pair { .. } = fn_abi.ret.mode {
+        let _ = WasmCAbi::Legacy;
+        span_bug!(
+            tcx.def_span(def_id),
+            "cannot return a pair (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666"
+        );
+    }
+
+    let hidden_return = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
+
+    signature.push('(');
+
+    if hidden_return {
+        signature.push_str(ptr_type);
+        if !fn_abi.args.is_empty() {
+            signature.push_str(", ");
+        }
+    }
+
+    let mut it = fn_abi.args.iter().peekable();
+    while let Some(arg_abi) = it.next() {
+        wasm_type(tcx, &mut signature, arg_abi, ptr_type, def_id);
+        if it.peek().is_some() {
+            signature.push_str(", ");
+        }
+    }
+
+    signature.push_str(") -> (");
+
+    if !hidden_return {
+        wasm_type(tcx, &mut signature, &fn_abi.ret, ptr_type, def_id);
+    }
+
+    signature.push(')');
+
+    signature
+}
+
+fn wasm_type<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    signature: &mut String,
+    arg_abi: &ArgAbi<'_, Ty<'tcx>>,
+    ptr_type: &'static str,
+    def_id: DefId,
+) {
+    match arg_abi.mode {
+        PassMode::Ignore => { /* do nothing */ }
+        PassMode::Direct(_) => {
+            let direct_type = match arg_abi.layout.backend_repr {
+                BackendRepr::Scalar(scalar) => wasm_primitive(scalar.primitive(), ptr_type),
+                BackendRepr::Vector { .. } => "v128",
+                BackendRepr::Memory { .. } => {
+                    // FIXME: remove this branch once the wasm32-unknown-unknown ABI is fixed
+                    let _ = WasmCAbi::Legacy;
+                    span_bug!(
+                        tcx.def_span(def_id),
+                        "cannot use memory args (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666"
+                    );
+                }
+                other => unreachable!("unexpected BackendRepr: {:?}", other),
+            };
+
+            signature.push_str(direct_type);
+        }
+        PassMode::Pair(_, _) => match arg_abi.layout.backend_repr {
+            BackendRepr::ScalarPair(a, b) => {
+                signature.push_str(wasm_primitive(a.primitive(), ptr_type));
+                signature.push_str(", ");
+                signature.push_str(wasm_primitive(b.primitive(), ptr_type));
+            }
+            other => unreachable!("{other:?}"),
+        },
+        PassMode::Cast { pad_i32, ref cast } => {
+            // For wasm, Cast is used for single-field primitive wrappers like `struct Wrapper(i64);`
+            assert!(!pad_i32, "not currently used by wasm calling convention");
+            assert!(cast.prefix[0].is_none(), "no prefix");
+            assert_eq!(cast.rest.total, arg_abi.layout.size, "single item");
+
+            let wrapped_wasm_type = match cast.rest.unit.kind {
+                RegKind::Integer => match cast.rest.unit.size.bytes() {
+                    ..=4 => "i32",
+                    ..=8 => "i64",
+                    _ => ptr_type,
+                },
+                RegKind::Float => match cast.rest.unit.size.bytes() {
+                    ..=4 => "f32",
+                    ..=8 => "f64",
+                    _ => ptr_type,
+                },
+                RegKind::Vector => "v128",
+            };
+
+            signature.push_str(wrapped_wasm_type);
+        }
+        PassMode::Indirect { .. } => signature.push_str(ptr_type),
+    }
+}
+
+fn wasm_primitive(primitive: Primitive, ptr_type: &'static str) -> &'static str {
+    match primitive {
+        Primitive::Int(integer, _) => match integer {
+            Integer::I8 | Integer::I16 | Integer::I32 => "i32",
+            Integer::I64 => "i64",
+            Integer::I128 => "i64, i64",
+        },
+        Primitive::Float(float) => match float {
+            Float::F16 | Float::F32 => "f32",
+            Float::F64 => "f64",
+            Float::F128 => "i64, i64",
+        },
+        Primitive::Pointer(_) => ptr_type,
+    }
+}
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 19101ec2d1b..9ca7d4f8f00 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -204,14 +204,30 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
         let alloc_align = alloc.inner().align;
         assert!(alloc_align >= layout.align.abi);
 
+        // Returns `None` when the value is partially undefined or any byte of it has provenance.
+        // Otherwise returns the value or (if the entire value is undef) returns an undef.
         let read_scalar = |start, size, s: abi::Scalar, ty| {
+            let range = alloc_range(start, size);
             match alloc.0.read_scalar(
                 bx,
-                alloc_range(start, size),
+                range,
                 /*read_provenance*/ matches!(s.primitive(), abi::Primitive::Pointer(_)),
             ) {
-                Ok(val) => bx.scalar_to_backend(val, s, ty),
-                Err(_) => bx.const_poison(ty),
+                Ok(val) => Some(bx.scalar_to_backend(val, s, ty)),
+                Err(_) => {
+                    // We may have failed due to partial provenance or unexpected provenance,
+                    // continue down the normal code path if so.
+                    if alloc.0.provenance().range_empty(range, &bx.tcx())
+                        // Since `read_scalar` failed, but there were no relocations involved, the
+                        // bytes must be partially or fully uninitialized. Thus we can now unwrap the
+                        // information about the range of uninit bytes and check if it's the full range.
+                        && alloc.0.init_mask().is_range_initialized(range).unwrap_err() == range
+                    {
+                        Some(bx.const_undef(ty))
+                    } else {
+                        None
+                    }
+                }
             }
         };
 
@@ -222,16 +238,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
         // check that walks over the type of `mplace` to make sure it is truly correct to treat this
         // like a `Scalar` (or `ScalarPair`).
         match layout.backend_repr {
-            BackendRepr::Scalar(s @ abi::Scalar::Initialized { .. }) => {
+            BackendRepr::Scalar(s) => {
                 let size = s.size(bx);
                 assert_eq!(size, layout.size, "abi::Scalar size does not match layout size");
-                let val = read_scalar(offset, size, s, bx.immediate_backend_type(layout));
-                OperandRef { val: OperandValue::Immediate(val), layout }
+                if let Some(val) = read_scalar(offset, size, s, bx.immediate_backend_type(layout)) {
+                    return OperandRef { val: OperandValue::Immediate(val), layout };
+                }
             }
-            BackendRepr::ScalarPair(
-                a @ abi::Scalar::Initialized { .. },
-                b @ abi::Scalar::Initialized { .. },
-            ) => {
+            BackendRepr::ScalarPair(a, b) => {
                 let (a_size, b_size) = (a.size(bx), b.size(bx));
                 let b_offset = (offset + a_size).align_to(b.align(bx).abi);
                 assert!(b_offset.bytes() > 0);
@@ -247,20 +261,21 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
                     b,
                     bx.scalar_pair_element_backend_type(layout, 1, true),
                 );
-                OperandRef { val: OperandValue::Pair(a_val, b_val), layout }
-            }
-            _ if layout.is_zst() => OperandRef::zero_sized(layout),
-            _ => {
-                // Neither a scalar nor scalar pair. Load from a place
-                // FIXME: should we cache `const_data_from_alloc` to avoid repeating this for the
-                // same `ConstAllocation`?
-                let init = bx.const_data_from_alloc(alloc);
-                let base_addr = bx.static_addr_of(init, alloc_align, None);
-
-                let llval = bx.const_ptr_byte_offset(base_addr, offset);
-                bx.load_operand(PlaceRef::new_sized(llval, layout))
+                if let (Some(a_val), Some(b_val)) = (a_val, b_val) {
+                    return OperandRef { val: OperandValue::Pair(a_val, b_val), layout };
+                }
             }
+            _ if layout.is_zst() => return OperandRef::zero_sized(layout),
+            _ => {}
         }
+        // Neither a scalar nor scalar pair. Load from a place
+        // FIXME: should we cache `const_data_from_alloc` to avoid repeating this for the
+        // same `ConstAllocation`?
+        let init = bx.const_data_from_alloc(alloc);
+        let base_addr = bx.static_addr_of(init, alloc_align, None);
+
+        let llval = bx.const_ptr_byte_offset(base_addr, offset);
+        bx.load_operand(PlaceRef::new_sized(llval, layout))
     }
 
     /// Asserts that this operand refers to a scalar and returns
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index eb4ef599b82..e775d219c7b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -8,7 +8,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_session::config::OptLevel;
 use rustc_span::{DUMMY_SP, Span};
-use tracing::{debug, instrument};
+use tracing::{debug, instrument, trace};
 
 use super::operand::{OperandRef, OperandValue};
 use super::place::PlaceRef;
@@ -93,6 +93,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     return;
                 }
 
+                // If `v` is an integer constant whose value is just a single byte repeated N times,
+                // emit a `memset` filling the entire `dest` with that byte.
                 let try_init_all_same = |bx: &mut Bx, v| {
                     let start = dest.val.llval;
                     let size = bx.const_usize(dest.layout.size.bytes());
@@ -117,13 +119,33 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     false
                 };
 
+                trace!(?cg_elem.val);
                 match cg_elem.val {
                     OperandValue::Immediate(v) => {
                         if try_init_all_same(bx, v) {
                             return;
                         }
                     }
-                    _ => (),
+                    OperandValue::Pair(a, b) => {
+                        let a_is_undef = bx.cx().is_undef(a);
+                        match (a_is_undef, bx.cx().is_undef(b)) {
+                            // Can happen for uninit unions
+                            (true, true) => {
+                                // FIXME: can we produce better output here?
+                            }
+                            (false, true) | (true, false) => {
+                                let val = if a_is_undef { b } else { a };
+                                if try_init_all_same(bx, val) {
+                                    return;
+                                }
+                            }
+                            (false, false) => {
+                                // FIXME: if both are the same value, use try_init_all_same
+                            }
+                        }
+                    }
+                    OperandValue::ZeroSized => unreachable!("checked above"),
+                    OperandValue::Ref(..) => {}
                 }
 
                 let count = self
@@ -365,10 +387,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         use abi::Primitive::*;
         imm = bx.from_immediate(imm);
 
-        // When scalars are passed by value, there's no metadata recording their
-        // valid ranges. For example, `char`s are passed as just `i32`, with no
-        // way for LLVM to know that they're 0x10FFFF at most. Thus we assume
-        // the range of the input value too, not just the output range.
+        // If we have a scalar, we must already know its range. Either
+        //
+        // 1) It's a parameter with `range` parameter metadata,
+        // 2) It's something we `load`ed with `!range` metadata, or
+        // 3) After a transmute we `assume`d the range (see below).
+        //
+        // That said, last time we tried removing this, it didn't actually help
+        // the rustc-perf results, so might as well keep doing it
+        // <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182>
         self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
 
         imm = match (from_scalar.primitive(), to_scalar.primitive()) {
@@ -389,7 +416,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 bx.bitcast(int_imm, to_backend_ty)
             }
         };
+
+        // This `assume` remains important for cases like (a conceptual)
+        //    transmute::<u32, NonZeroU32>(x) == 0
+        // since it's never passed to something with parameter metadata (especially
+        // after MIR inlining) so the only way to tell the backend about the
+        // constraint that the `transmute` introduced is to `assume` it.
         self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
+
         imm = bx.to_immediate_scalar(imm, to_scalar);
         imm
     }
@@ -411,31 +445,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             return;
         }
 
-        let abi::WrappingRange { start, end } = scalar.valid_range(self.cx);
-
-        if start <= end {
-            if start > 0 {
-                let low = bx.const_uint_big(backend_ty, start);
-                let cmp = bx.icmp(IntPredicate::IntUGE, imm, low);
-                bx.assume(cmp);
-            }
-
-            let type_max = scalar.size(self.cx).unsigned_int_max();
-            if end < type_max {
-                let high = bx.const_uint_big(backend_ty, end);
-                let cmp = bx.icmp(IntPredicate::IntULE, imm, high);
-                bx.assume(cmp);
-            }
-        } else {
-            let low = bx.const_uint_big(backend_ty, start);
-            let cmp_low = bx.icmp(IntPredicate::IntUGE, imm, low);
-
-            let high = bx.const_uint_big(backend_ty, end);
-            let cmp_high = bx.icmp(IntPredicate::IntULE, imm, high);
-
-            let or = bx.or(cmp_low, cmp_high);
-            bx.assume(or);
-        }
+        let range = scalar.valid_range(self.cx);
+        bx.assume_integer_range(imm, backend_ty, range);
     }
 
     pub(crate) fn codegen_rvalue_unsized(
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 3ee13b19f66..bbf87a59942 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -217,6 +217,27 @@ pub trait BuilderMethods<'a, 'tcx>:
         dest: PlaceRef<'tcx, Self::Value>,
     );
 
+    /// Emits an `assume` that the integer value `imm` of type `ty` is contained in `range`.
+    ///
+    /// This *always* emits the assumption, so you probably want to check the
+    /// optimization level and `Scalar::is_always_valid` before calling it.
+    fn assume_integer_range(&mut self, imm: Self::Value, ty: Self::Type, range: WrappingRange) {
+        let WrappingRange { start, end } = range;
+
+        // Perhaps one day we'll be able to use assume operand bundles for this,
+        // but for now this encoding with a single icmp+assume is best per
+        // <https://github.com/llvm/llvm-project/issues/123278#issuecomment-2597440158>
+        let shifted = if start == 0 {
+            imm
+        } else {
+            let low = self.const_uint_big(ty, start);
+            self.sub(imm, low)
+        };
+        let width = self.const_uint_big(ty, u128::wrapping_sub(end, start));
+        let cmp = self.icmp(IntPredicate::IntULE, shifted, width);
+        self.assume(cmp);
+    }
+
     fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
     fn nonnull_metadata(&mut self, load: Self::Value);
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs
index 9af463a691a..d0de7ff0b5f 100644
--- a/compiler/rustc_codegen_ssa/src/traits/consts.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs
@@ -9,6 +9,7 @@ pub trait ConstCodegenMethods<'tcx>: BackendTypes {
     /// Generate an uninitialized value (matching uninitialized memory in MIR).
     /// Whether memory is initialized or not is tracked byte-for-byte.
     fn const_undef(&self, t: Self::Type) -> Self::Value;
+    fn is_undef(&self, v: Self::Value) -> bool;
     /// Generate a fake value. Poison always affects the entire value, even if just a single byte is
     /// poison. This can only be used in codepaths that are already UB, i.e., UB-free Rust code
     /// (including code that e.g. copies uninit memory with `MaybeUninit`) can never encounter a
diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs
index 51e2255efe1..97fe614aa10 100644
--- a/compiler/rustc_codegen_ssa/src/traits/write.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/write.rs
@@ -1,7 +1,6 @@
 use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
 use rustc_errors::{DiagCtxtHandle, FatalError};
 use rustc_middle::dep_graph::WorkProduct;
-use rustc_middle::ty::TyCtxt;
 
 use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
 use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig};
@@ -65,7 +64,6 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
     fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
     fn autodiff(
         cgcx: &CodegenContext<Self>,
-        tcx: TyCtxt<'_>,
         module: &ModuleCodegen<Self::Module>,
         diff_fncs: Vec<AutoDiffItem>,
         config: &ModuleConfig,
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index d4bfb781320..485c8696342 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -416,7 +416,7 @@ const_eval_unsized_local = unsized locals are not supported
 const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
 const_eval_unstable_in_stable_exposed =
     const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]`
-    .is_function_call = mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+    .is_function_call = mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features
     .unstable_sugg = if the {$is_function_call2 ->
             [true] caller
             *[false] function
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index fee7287951d..cc21a18af3a 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -140,7 +140,7 @@ where
         // Don't emit a new diagnostic for these errors, they are already reported elsewhere or
         // should remain silent.
         err_inval!(AlreadyReported(info)) => ErrorHandled::Reported(info, span),
-        err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
+        err_inval!(Layout(LayoutError::TooGeneric(_))) | err_inval!(TooGeneric) => {
             ErrorHandled::TooGeneric(span)
         }
         err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index c8ecddb046c..889a8299c18 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -32,7 +32,7 @@ tracing = "0.1"
 version = "0.12"
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.57.0"
+version = "0.59.0"
 features = [
     "Win32_Foundation",
     "Win32_Storage_FileSystem",
diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs
index 9739e501272..e761faee67b 100644
--- a/compiler/rustc_data_structures/src/flock/windows.rs
+++ b/compiler/rustc_data_structures/src/flock/windows.rs
@@ -60,9 +60,9 @@ impl Lock {
 
         unsafe {
             LockFileEx(
-                HANDLE(file.as_raw_handle() as isize),
+                HANDLE(file.as_raw_handle()),
                 flags,
-                0,
+                None,
                 u32::MAX,
                 u32::MAX,
                 &mut overlapped,
diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs
index 92035e8bc48..4a1e5db6768 100644
--- a/compiler/rustc_data_structures/src/graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/mod.rs
@@ -14,7 +14,23 @@ mod tests;
 pub trait DirectedGraph {
     type Node: Idx;
 
+    /// Returns the total number of nodes in this graph.
+    ///
+    /// Several graph algorithm implementations assume that every node ID is
+    /// strictly less than the number of nodes, i.e. nodes are densely numbered.
+    /// That assumption allows them to use `num_nodes` to allocate per-node
+    /// data structures, indexed by node.
     fn num_nodes(&self) -> usize;
+
+    /// Iterates over all nodes of a graph in ascending numeric order.
+    ///
+    /// Assumes that nodes are densely numbered, i.e. every index in
+    /// `0..num_nodes` is a valid node.
+    fn iter_nodes(
+        &self,
+    ) -> impl Iterator<Item = Self::Node> + DoubleEndedIterator + ExactSizeIterator {
+        (0..self.num_nodes()).map(<Self::Node as Idx>::new)
+    }
 }
 
 pub trait NumEdges: DirectedGraph {
diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs
index 06fedef00fc..93f6192b10b 100644
--- a/compiler/rustc_data_structures/src/graph/scc/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs
@@ -333,8 +333,8 @@ where
             to_annotation,
         };
 
-        let scc_indices = (0..num_nodes)
-            .map(G::Node::new)
+        let scc_indices = graph
+            .iter_nodes()
             .map(|node| match this.start_walk_from(node) {
                 WalkReturn::Complete { scc_index, .. } => scc_index,
                 WalkReturn::Cycle { min_depth, .. } => {
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index 2f0fe64b096..07b88e59723 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -59,7 +59,7 @@ libc = "0.2"
 # tidy-alphabetical-end
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.57.0"
+version = "0.59.0"
 features = [
     "Win32_System_Diagnostics_Debug",
 ]
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index f7e7aa64614..20be2144609 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -28,8 +28,8 @@ use std::io::{self, IsTerminal, Read, Write};
 use std::panic::{self, PanicHookInfo, catch_unwind};
 use std::path::{Path, PathBuf};
 use std::process::{self, Command, Stdio};
+use std::sync::OnceLock;
 use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, OnceLock};
 use std::time::{Instant, SystemTime};
 use std::{env, str};
 
@@ -53,14 +53,13 @@ use rustc_middle::ty::TyCtxt;
 use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
 use rustc_session::config::{
     CG_OPTIONS, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, UnstableOptions,
-    Z_OPTIONS, nightly_options,
+    Z_OPTIONS, nightly_options, parse_target_triple,
 };
 use rustc_session::getopts::{self, Matches};
 use rustc_session::lint::{Lint, LintId};
 use rustc_session::output::collect_crate_types;
 use rustc_session::{EarlyDiagCtxt, Session, config, filesearch};
 use rustc_span::FileName;
-use rustc_span::source_map::FileLoader;
 use rustc_target::json::ToJson;
 use rustc_target::spec::{Target, TargetTuple};
 use time::OffsetDateTime;
@@ -208,84 +207,7 @@ pub fn diagnostics_registry() -> Registry {
 }
 
 /// This is the primary entry point for rustc.
-pub struct RunCompiler<'a> {
-    at_args: &'a [String],
-    callbacks: &'a mut (dyn Callbacks + Send),
-    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    make_codegen_backend:
-        Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
-    using_internal_features: Arc<std::sync::atomic::AtomicBool>,
-}
-
-impl<'a> RunCompiler<'a> {
-    pub fn new(at_args: &'a [String], callbacks: &'a mut (dyn Callbacks + Send)) -> Self {
-        Self {
-            at_args,
-            callbacks,
-            file_loader: None,
-            make_codegen_backend: None,
-            using_internal_features: Arc::default(),
-        }
-    }
-
-    /// Set a custom codegen backend.
-    ///
-    /// Has no uses within this repository, but is used by bjorn3 for "the
-    /// hotswapping branch of cg_clif" for "setting the codegen backend from a
-    /// custom driver where the custom codegen backend has arbitrary data."
-    /// (See #102759.)
-    pub fn set_make_codegen_backend(
-        &mut self,
-        make_codegen_backend: Option<
-            Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
-        >,
-    ) -> &mut Self {
-        self.make_codegen_backend = make_codegen_backend;
-        self
-    }
-
-    /// Load files from sources other than the file system.
-    ///
-    /// Has no uses within this repository, but may be used in the future by
-    /// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for
-    /// running rustc without having to save". (See #102759.)
-    pub fn set_file_loader(
-        &mut self,
-        file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    ) -> &mut Self {
-        self.file_loader = file_loader;
-        self
-    }
-
-    /// Set the session-global flag that checks whether internal features have been used,
-    /// suppressing the message about submitting an issue in ICEs when enabled.
-    #[must_use]
-    pub fn set_using_internal_features(mut self, using_internal_features: Arc<AtomicBool>) -> Self {
-        self.using_internal_features = using_internal_features;
-        self
-    }
-
-    /// Parse args and run the compiler.
-    pub fn run(self) {
-        run_compiler(
-            self.at_args,
-            self.callbacks,
-            self.file_loader,
-            self.make_codegen_backend,
-            self.using_internal_features,
-        );
-    }
-}
-
-fn run_compiler(
-    at_args: &[String],
-    callbacks: &mut (dyn Callbacks + Send),
-    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    make_codegen_backend: Option<
-        Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
-    >,
-    using_internal_features: Arc<std::sync::atomic::AtomicBool>,
-) {
+pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) {
     let mut default_early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
 
     // Throw away the first argument, the name of the binary.
@@ -322,16 +244,16 @@ fn run_compiler(
         output_file: ofile,
         output_dir: odir,
         ice_file,
-        file_loader,
+        file_loader: None,
         locale_resources: DEFAULT_LOCALE_RESOURCES.to_vec(),
         lint_caps: Default::default(),
         psess_created: None,
         hash_untracked_state: None,
         register_lints: None,
         override_queries: None,
-        make_codegen_backend,
+        make_codegen_backend: None,
         registry: diagnostics_registry(),
-        using_internal_features,
+        using_internal_features: &USING_INTERNAL_FEATURES,
         expanded_args: args,
     };
 
@@ -916,13 +838,7 @@ pub fn version_at_macro_invocation(
         safe_println!("host: {}", config::host_tuple());
         safe_println!("release: {release}");
 
-        let debug_flags = matches.opt_strs("Z");
-        let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
-        let opts = config::Options::default();
-        let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone());
-        let target = config::build_target_config(early_dcx, &opts, &sysroot);
-
-        get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_version();
+        get_backend_from_raw_matches(early_dcx, matches).print_version();
     }
 }
 
@@ -1125,19 +1041,32 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) ->
     }
 
     if cg_flags.iter().any(|x| *x == "passes=list") {
-        let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
-
-        let opts = config::Options::default();
-        let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone());
-        let target = config::build_target_config(early_dcx, &opts, &sysroot);
-
-        get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_passes();
+        get_backend_from_raw_matches(early_dcx, matches).print_passes();
         return true;
     }
 
     false
 }
 
+/// Get the codegen backend based on the raw [`Matches`].
+///
+/// `rustc -vV` and `rustc -Cpasses=list` need to get the codegen backend before we have parsed all
+/// arguments and created a [`Session`]. This function reads `-Zcodegen-backend`, `--target` and
+/// `--sysroot` without validating any other arguments and loads the codegen backend based on these
+/// arguments.
+fn get_backend_from_raw_matches(
+    early_dcx: &EarlyDiagCtxt,
+    matches: &Matches,
+) -> Box<dyn CodegenBackend> {
+    let debug_flags = matches.opt_strs("Z");
+    let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
+    let target = parse_target_triple(early_dcx, matches);
+    let sysroot = filesearch::materialize_sysroot(matches.opt_str("sysroot").map(PathBuf::from));
+    let target = config::build_target_config(early_dcx, &target, &sysroot);
+
+    get_codegen_backend(early_dcx, &sysroot, backend_name, &target)
+}
+
 fn describe_debug_flags() {
     safe_println!("\nAvailable options:\n");
     print_flag_list("-Z", config::Z_OPTIONS);
@@ -1343,6 +1272,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat
     })
 }
 
+pub static USING_INTERNAL_FEATURES: AtomicBool = AtomicBool::new(false);
+
 /// Installs a panic hook that will print the ICE message on unexpected panics.
 ///
 /// The hook is intended to be useable even by external tools. You can pass a custom
@@ -1353,15 +1284,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat
 /// If you have no extra info to report, pass the empty closure `|_| ()` as the argument to
 /// extra_info.
 ///
-/// Returns a flag that can be set to disable the note for submitting a bug. This can be passed to
-/// [`RunCompiler::set_using_internal_features`] to let macro expansion set it when encountering
-/// internal features.
-///
 /// A custom rustc driver can skip calling this to set up a custom ICE hook.
-pub fn install_ice_hook(
-    bug_report_url: &'static str,
-    extra_info: fn(&DiagCtxt),
-) -> Arc<AtomicBool> {
+pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&DiagCtxt)) {
     // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
     // full backtraces. When a compiler ICE happens, we want to gather
     // as much information as possible to present in the issue opened
@@ -1378,8 +1302,6 @@ pub fn install_ice_hook(
         }
     }
 
-    let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default());
-    let using_internal_features_hook = Arc::clone(&using_internal_features);
     panic::update_hook(Box::new(
         move |default_hook: &(dyn Fn(&PanicHookInfo<'_>) + Send + Sync + 'static),
               info: &PanicHookInfo<'_>| {
@@ -1431,11 +1353,9 @@ pub fn install_ice_hook(
             }
 
             // Print the ICE message
-            report_ice(info, bug_report_url, extra_info, &using_internal_features_hook);
+            report_ice(info, bug_report_url, extra_info, &USING_INTERNAL_FEATURES);
         },
     ));
-
-    using_internal_features
 }
 
 /// Prints the ICE message, including query stack, but without backtrace.
@@ -1521,9 +1441,9 @@ fn report_ice(
     // If backtraces are enabled, also print the query stack
     let backtrace = env::var_os("RUST_BACKTRACE").is_some_and(|x| &x != "0");
 
-    let num_frames = if backtrace { None } else { Some(2) };
+    let limit_frames = if backtrace { None } else { Some(2) };
 
-    interface::try_print_query_stack(dcx, num_frames, file);
+    interface::try_print_query_stack(dcx, limit_frames, file);
 
     // We don't trust this callback not to panic itself, so run it at the end after we're sure we've
     // printed all the relevant info.
@@ -1576,13 +1496,11 @@ pub fn main() -> ! {
     init_rustc_env_logger(&early_dcx);
     signal_handler::install();
     let mut callbacks = TimePassesCallbacks::default();
-    let using_internal_features = install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
+    install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
     install_ctrlc_handler();
 
     let exit_code = catch_with_exit_code(|| {
-        RunCompiler::new(&args::raw_args(&early_dcx)?, &mut callbacks)
-            .set_using_internal_features(using_internal_features)
-            .run();
+        run_compiler(&args::raw_args(&early_dcx)?, &mut callbacks);
         Ok(())
     });
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md
index 014d8c4f761..4b06395897a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0038.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0038.md
@@ -264,15 +264,15 @@ trait Foo {
 ### Trait contains associated constants
 
 Just like static functions, associated constants aren't stored on the method
-table. If the trait or any subtrait contain an associated constant, they cannot
-be made into an object.
+table. If the trait or any subtrait contain an associated constant, they are not
+dyn compatible.
 
 ```compile_fail,E0038
 trait Foo {
     const X: i32;
 }
 
-impl Foo {}
+impl dyn Foo {}
 ```
 
 A simple workaround is to use a helper method instead:
diff --git a/compiler/rustc_error_codes/src/error_codes/E0132.md b/compiler/rustc_error_codes/src/error_codes/E0132.md
index 51258739b89..cbb14510ed7 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0132.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0132.md
@@ -1,32 +1,3 @@
-A function with the `start` attribute was declared with type parameters.
-
-Erroneous code example:
-
-```compile_fail,E0132
-#![feature(start)]
-
-#[start]
-fn f<T>() {}
-```
-
-It is not possible to declare type parameters on a function that has the `start`
-attribute. Such a function must have the following type signature (for more
-information, view [the unstable book][1]):
+#### Note: this error code is no longer emitted by the compiler.
 
-[1]: https://doc.rust-lang.org/unstable-book/language-features/start.html
-
-```
-# let _:
-fn(isize, *const *const u8) -> isize;
-```
-
-Example:
-
-```
-#![feature(start)]
-
-#[start]
-fn my_start(argc: isize, argv: *const *const u8) -> isize {
-    0
-}
-```
+A function with the `start` attribute was declared with type parameters.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0138.md b/compiler/rustc_error_codes/src/error_codes/E0138.md
index 3f5eaea9f98..2e6ba546a16 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0138.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0138.md
@@ -1,25 +1,3 @@
-More than one function was declared with the `#[start]` attribute.
-
-Erroneous code example:
-
-```compile_fail,E0138
-#![feature(start)]
-
-#[start]
-fn foo(argc: isize, argv: *const *const u8) -> isize {}
+#### Note: this error code is no longer emitted by the compiler.
 
-#[start]
-fn f(argc: isize, argv: *const *const u8) -> isize {}
-// error: multiple 'start' functions
-```
-
-This error indicates that the compiler found multiple functions with the
-`#[start]` attribute. This is an error because there must be a unique entry
-point into a Rust program. Example:
-
-```
-#![feature(start)]
-
-#[start]
-fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } // ok!
-```
+More than one function was declared with the `#[start]` attribute.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0393.md b/compiler/rustc_error_codes/src/error_codes/E0393.md
index 50225b25163..c7260815905 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0393.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0393.md
@@ -3,12 +3,10 @@ A type parameter which references `Self` in its default value was not specified.
 Erroneous code example:
 
 ```compile_fail,E0393
-trait A<T=Self> {}
+trait A<T = Self> {}
 
-fn together_we_will_rule_the_galaxy(son: &A) {}
-// error: the type parameter `T` must be explicitly specified in an
-//        object type because its default value `Self` references the
-//        type `Self`
+fn together_we_will_rule_the_galaxy(son: &dyn A) {}
+// error: the type parameter `T` must be explicitly specified
 ```
 
 A trait object is defined over a single, fully-defined trait. With a regular
@@ -23,7 +21,7 @@ disallowed. Making the trait concrete by explicitly specifying the value of the
 defaulted parameter will fix this issue. Fixed example:
 
 ```
-trait A<T=Self> {}
+trait A<T = Self> {}
 
-fn together_we_will_rule_the_galaxy(son: &A<i32>) {} // Ok!
+fn together_we_will_rule_the_galaxy(son: &dyn A<i32>) {} // Ok!
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0433.md b/compiler/rustc_error_codes/src/error_codes/E0433.md
index 5a64c13c9af..36e4b66e8dc 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0433.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0433.md
@@ -19,7 +19,7 @@ If you've expected to use a crate name:
 
 ```compile_fail
 use ferris_wheel::BigO;
-// error: failed to resolve: use of undeclared crate or module `ferris_wheel`
+// error: failed to resolve: use of undeclared module or unlinked crate
 ```
 
 Make sure the crate has been added as a dependency in `Cargo.toml`.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0647.md b/compiler/rustc_error_codes/src/error_codes/E0647.md
index 59bb47ba62a..e2f14b81aa6 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0647.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0647.md
@@ -1,13 +1,3 @@
-The `start` function was defined with a where clause.
-
-Erroneous code example:
+#### Note: this error code is no longer emitted by the compiler.
 
-```compile_fail,E0647
-#![feature(start)]
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize where (): Copy {
-    //^ error: `#[start]` function is not allowed to have a where clause
-    0
-}
-```
+The `start` function was defined with a where clause.
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index 29f3277d399..0a30bdb48a0 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -24,6 +24,10 @@
 //
 // Both columns are necessary because it's not possible in Rust to create a new identifier such as
 // `E0123` from an integer literal such as `0123`, unfortunately.
+//
+// Do *not* remove entries from this list. Instead, just add a note th the corresponding markdown
+// file saying that this error is not emitted by the compiler any more (see E0001.md for an
+// example), and remove all code examples that do not build any more.
 #[macro_export]
 macro_rules! error_codes {
     ($macro:path) => (
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index 66b9adbead0..fbb6a1cc475 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -31,7 +31,7 @@ tracing = "0.1"
 # tidy-alphabetical-end
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.57.0"
+version = "0.59.0"
 features = [
     "Win32_Foundation",
     "Win32_Security",
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index f938352820d..991dfa1821a 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -3146,7 +3146,7 @@ impl FileWithAnnotatedLines {
                     add_annotation_to_file(&mut output, Lrc::clone(&file), line, ann.as_line());
                 }
                 let line_end = ann.line_end - 1;
-                let end_is_empty = file.get_line(line_end - 1).map_or(false, |s| !filter(&s));
+                let end_is_empty = file.get_line(line_end - 1).is_some_and(|s| !filter(&s));
                 if middle < line_end && !end_is_empty {
                     add_annotation_to_file(&mut output, Lrc::clone(&file), line_end, ann.as_line());
                 }
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 97df7f9265a..95c81fc5f44 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -21,7 +21,7 @@ use rustc_error_messages::FluentArgs;
 use rustc_lint_defs::Applicability;
 use rustc_span::Span;
 use rustc_span::hygiene::ExpnData;
-use rustc_span::source_map::SourceMap;
+use rustc_span::source_map::{FilePathMapping, SourceMap};
 use serde::Serialize;
 use termcolor::{ColorSpec, WriteColor};
 
@@ -45,7 +45,7 @@ pub struct JsonEmitter {
     #[setters(skip)]
     dst: IntoDynSyncSend<Box<dyn Write + Send>>,
     #[setters(skip)]
-    sm: Lrc<SourceMap>,
+    sm: Option<Lrc<SourceMap>>,
     fluent_bundle: Option<Lrc<FluentBundle>>,
     #[setters(skip)]
     fallback_bundle: LazyFallbackBundle,
@@ -65,7 +65,7 @@ pub struct JsonEmitter {
 impl JsonEmitter {
     pub fn new(
         dst: Box<dyn Write + Send>,
-        sm: Lrc<SourceMap>,
+        sm: Option<Lrc<SourceMap>>,
         fallback_bundle: LazyFallbackBundle,
         pretty: bool,
         json_rendered: HumanReadableErrorType,
@@ -171,7 +171,7 @@ impl Emitter for JsonEmitter {
     }
 
     fn source_map(&self) -> Option<&SourceMap> {
-        Some(&self.sm)
+        self.sm.as_deref()
     }
 
     fn should_show_explain(&self) -> bool {
@@ -371,7 +371,7 @@ impl Diagnostic {
         }
         HumanEmitter::new(dst, Lrc::clone(&je.fallback_bundle))
             .short_message(short)
-            .sm(Some(Lrc::clone(&je.sm)))
+            .sm(je.sm.clone())
             .fluent_bundle(je.fluent_bundle.clone())
             .diagnostic_width(je.diagnostic_width)
             .macro_backtrace(je.macro_backtrace)
@@ -458,22 +458,34 @@ impl DiagnosticSpan {
         mut backtrace: impl Iterator<Item = ExpnData>,
         je: &JsonEmitter,
     ) -> DiagnosticSpan {
-        let start = je.sm.lookup_char_pos(span.lo());
+        let empty_source_map;
+        let sm = match &je.sm {
+            Some(s) => s,
+            None => {
+                span = rustc_span::DUMMY_SP;
+                empty_source_map = Arc::new(SourceMap::new(FilePathMapping::empty()));
+                empty_source_map
+                    .new_source_file(std::path::PathBuf::from("empty.rs").into(), String::new());
+                &empty_source_map
+            }
+        };
+        let start = sm.lookup_char_pos(span.lo());
         // If this goes from the start of a line to the end and the replacement
         // is an empty string, increase the length to include the newline so we don't
         // leave an empty line
         if start.col.0 == 0
-            && suggestion.map_or(false, |(s, _)| s.is_empty())
-            && let Ok(after) = je.sm.span_to_next_source(span)
+            && let Some((suggestion, _)) = suggestion
+            && suggestion.is_empty()
+            && let Ok(after) = sm.span_to_next_source(span)
             && after.starts_with('\n')
         {
             span = span.with_hi(span.hi() + rustc_span::BytePos(1));
         }
-        let end = je.sm.lookup_char_pos(span.hi());
+        let end = sm.lookup_char_pos(span.hi());
         let backtrace_step = backtrace.next().map(|bt| {
             let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je);
             let def_site_span = Self::from_span_full(
-                je.sm.guess_head_span(bt.def_site),
+                sm.guess_head_span(bt.def_site),
                 false,
                 None,
                 None,
@@ -488,7 +500,7 @@ impl DiagnosticSpan {
         });
 
         DiagnosticSpan {
-            file_name: je.sm.filename_for_diagnostics(&start.file.name).to_string(),
+            file_name: sm.filename_for_diagnostics(&start.file.name).to_string(),
             byte_start: start.file.original_relative_byte_pos(span.lo()).0,
             byte_end: start.file.original_relative_byte_pos(span.hi()).0,
             line_start: start.line,
@@ -558,19 +570,20 @@ impl DiagnosticSpanLine {
     /// `span` within the line.
     fn from_span(span: Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> {
         je.sm
-            .span_to_lines(span)
-            .map(|lines| {
+            .as_ref()
+            .and_then(|sm| {
+                let lines = sm.span_to_lines(span).ok()?;
                 // We can't get any lines if the source is unavailable.
                 if !should_show_source_code(
                     &je.ignored_directories_in_source_blocks,
-                    &je.sm,
+                    &sm,
                     &lines.file,
                 ) {
-                    return vec![];
+                    return None;
                 }
 
                 let sf = &*lines.file;
-                lines
+                let span_lines = lines
                     .lines
                     .iter()
                     .map(|line| {
@@ -581,8 +594,9 @@ impl DiagnosticSpanLine {
                             line.end_col.0 + 1,
                         )
                     })
-                    .collect()
+                    .collect();
+                Some(span_lines)
             })
-            .unwrap_or_else(|_| vec![])
+            .unwrap_or_default()
     }
 }
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index 0de555b83d3..cebaf7c1cfe 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -47,7 +47,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
         let output = Arc::new(Mutex::new(Vec::new()));
         let je = JsonEmitter::new(
             Box::new(Shared { data: output.clone() }),
-            sm,
+            Some(sm),
             fallback_bundle,
             true, // pretty
             HumanReadableErrorType::Short,
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index cc5eb9c335e..549729548f5 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -35,6 +35,7 @@ use std::backtrace::{Backtrace, BacktraceStatus};
 use std::borrow::Cow;
 use std::cell::Cell;
 use std::error::Report;
+use std::ffi::OsStr;
 use std::hash::Hash;
 use std::io::Write;
 use std::num::NonZero;
@@ -1717,7 +1718,7 @@ impl DiagCtxtInner {
         let bugs: Vec<_> =
             std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
 
-        let backtrace = std::env::var_os("RUST_BACKTRACE").map_or(true, |x| &x != "0");
+        let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
         let decorate = backtrace || self.ice_file.is_none();
         let mut out = self
             .ice_file
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 3e3f35332e0..83255b82017 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -391,7 +391,7 @@ impl<'a> StripUnconfigured<'a> {
         validate_attr::deny_builtin_meta_unsafety(&self.sess.psess, &meta_item);
 
         (
-            parse_cfg(&meta_item, self.sess).map_or(true, |meta_item| {
+            parse_cfg(&meta_item, self.sess).is_none_or(|meta_item| {
                 attr::cfg_matches(meta_item, &self.sess, self.lint_node_id, self.features)
             }),
             Some(meta_item),
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 9f48835e15d..e60a9e83184 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -159,7 +159,7 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match
                 if self
                     .best_failure
                     .as_ref()
-                    .map_or(true, |failure| failure.is_better_position(*approx_position))
+                    .is_none_or(|failure| failure.is_better_position(*approx_position))
                 {
                     self.best_failure = Some(BestFailure {
                         token: token.clone(),
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index ef209c2bce1..21688521ade 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -282,11 +282,13 @@ pub(super) fn transcribe<'a>(
                         }
                         MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
                             marker.visit_span(&mut sp);
+                            with_metavar_spans(|mspans| mspans.insert(ident.span, sp));
                             let kind = token::NtIdent(*ident, *is_raw);
                             TokenTree::token_alone(kind, sp)
                         }
                         MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => {
                             marker.visit_span(&mut sp);
+                            with_metavar_spans(|mspans| mspans.insert(ident.span, sp));
                             let kind = token::NtLifetime(*ident, *is_raw);
                             TokenTree::token_alone(kind, sp)
                         }
@@ -295,6 +297,8 @@ pub(super) fn transcribe<'a>(
                             // `Delimiter::Invisible` to maintain parsing priorities.
                             // `Interpolated` is currently used for such groups in rustc parser.
                             marker.visit_span(&mut sp);
+                            let use_span = nt.use_span();
+                            with_metavar_spans(|mspans| mspans.insert(use_span, sp));
                             TokenTree::token_alone(token::Interpolated(Lrc::clone(nt)), sp)
                         }
                         MatchedSeq(..) => {
@@ -410,19 +414,15 @@ fn maybe_use_metavar_location(
         return orig_tt.clone();
     }
 
-    let insert = |mspans: &mut FxHashMap<_, _>, s, ms| match mspans.try_insert(s, ms) {
-        Ok(_) => true,
-        Err(err) => *err.entry.get() == ms, // Tried to insert the same span, still success
-    };
     marker.visit_span(&mut metavar_span);
     let no_collision = match orig_tt {
         TokenTree::Token(token, ..) => {
-            with_metavar_spans(|mspans| insert(mspans, token.span, metavar_span))
+            with_metavar_spans(|mspans| mspans.insert(token.span, metavar_span))
         }
         TokenTree::Delimited(dspan, ..) => with_metavar_spans(|mspans| {
-            insert(mspans, dspan.open, metavar_span)
-                && insert(mspans, dspan.close, metavar_span)
-                && insert(mspans, dspan.entire(), metavar_span)
+            mspans.insert(dspan.open, metavar_span)
+                && mspans.insert(dspan.close, metavar_span)
+                && mspans.insert(dspan.entire(), metavar_span)
         }),
     };
     if no_collision || psess.source_map().is_imported(metavar_span) {
@@ -434,14 +434,14 @@ fn maybe_use_metavar_location(
     match orig_tt {
         TokenTree::Token(Token { kind, span }, spacing) => {
             let span = metavar_span.with_ctxt(span.ctxt());
-            with_metavar_spans(|mspans| insert(mspans, span, metavar_span));
+            with_metavar_spans(|mspans| mspans.insert(span, metavar_span));
             TokenTree::Token(Token { kind: kind.clone(), span }, *spacing)
         }
         TokenTree::Delimited(dspan, dspacing, delimiter, tts) => {
             let open = metavar_span.with_ctxt(dspan.open.ctxt());
             let close = metavar_span.with_ctxt(dspan.close.ctxt());
             with_metavar_spans(|mspans| {
-                insert(mspans, open, metavar_span) && insert(mspans, close, metavar_span)
+                mspans.insert(open, metavar_span) && mspans.insert(close, metavar_span)
             });
             let dspan = DelimSpan::from_pair(open, close);
             TokenTree::Delimited(dspan, *dspacing, *delimiter, tts.clone())
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 5510e7e09e5..17433eed9e7 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -408,11 +408,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), DuplicatesOk,
         EncodeCrossCrate::No,
     ),
-    // crate_id is deprecated
-    ungated!(
-        crate_id, CrateLevel, template!(NameValueStr: "ignored"), FutureWarnFollowing,
-        EncodeCrossCrate::No,
-    ),
 
     // ABI, linking, symbols, and FFI
     ungated!(
@@ -448,8 +443,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
 
     // Entry point:
-    ungated!(start, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
-    ungated!(no_start, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
     ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
 
     // Modules, prelude, and resolution:
@@ -533,7 +526,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     // RFC 2412
     gated!(
-        optimize, Normal, template!(List: "size|speed"), ErrorPreceding,
+        optimize, Normal, template!(List: "none|size|speed"), ErrorPreceding,
         EncodeCrossCrate::No, optimize_attribute, experimental!(optimize)
     ),
 
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 9aa59375706..081638715df 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -163,7 +163,7 @@ declare_features! (
     /// then removed. But there was no utility storing it separately, so now
     /// it's in this list.
     (removed, no_stack_check, "1.0.0", None, None),
-    /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible (object safe).
+    /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible (object safe).
     /// Renamed to `dyn_compatible_for_dispatch`.
     (removed, object_safe_for_dispatch, "1.83.0", Some(43561),
      Some("renamed to `dyn_compatible_for_dispatch`")),
@@ -220,8 +220,9 @@ declare_features! (
     (removed, rustc_diagnostic_macros, "1.38.0", None, None),
     /// Allows identifying crates that contain sanitizer runtimes.
     (removed, sanitizer_runtime, "1.17.0", None, None),
-    (removed, simd, "1.0.0", Some(27731),
-     Some("removed in favor of `#[repr(simd)]`")),
+    (removed, simd, "1.0.0", Some(27731), Some("removed in favor of `#[repr(simd)]`")),
+    /// Allows using `#[start]` on a function indicating that it is the program entrypoint.
+    (removed, start, "1.0.0", Some(29633), Some("not portable enough and never RFC'd")),
     /// Allows `#[link(kind = "static-nobundle", ...)]`.
     (removed, static_nobundle, "1.16.0", Some(37403),
      Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#)),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 4ab0bc47305..1a216ebf117 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -272,7 +272,7 @@ declare_features! (
     (unstable, doc_notable_trait, "1.52.0", Some(45040)),
     /// Allows using the `may_dangle` attribute (RFC 1327).
     (unstable, dropck_eyepatch, "1.10.0", Some(34761)),
-    /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible[^1].
+    /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible[^1].
     /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
     /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.
     ///
@@ -300,8 +300,6 @@ declare_features! (
     (internal, rustdoc_internals, "1.58.0", Some(90418)),
     /// Allows using the `rustdoc::missing_doc_code_examples` lint
     (unstable, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730)),
-    /// Allows using `#[start]` on a function indicating that it is the program entrypoint.
-    (unstable, start, "1.0.0", Some(29633)),
     /// Allows using `#[structural_match]` which indicates that a type is structurally matchable.
     /// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library
     /// feature with the same name exists.
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 705de389e07..7e3a8561da0 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -794,7 +794,7 @@ impl<Id> Res<Id> {
 
     /// Always returns `true` if `self` is `Res::Err`
     pub fn matches_ns(&self, ns: Namespace) -> bool {
-        self.ns().map_or(true, |actual_ns| actual_ns == ns)
+        self.ns().is_none_or(|actual_ns| actual_ns == ns)
     }
 
     /// Returns whether such a resolved path can occur in a tuple struct/variant pattern
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 5339feb5d27..a396d705cbb 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -15,6 +15,7 @@ pub use rustc_ast::{
 };
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::sorted_map::SortedMap;
+use rustc_data_structures::tagged_ptr::TaggedRef;
 use rustc_index::IndexVec;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::def_id::LocalDefId;
@@ -30,7 +31,7 @@ use crate::LangItem;
 use crate::def::{CtorKind, DefKind, Res};
 use crate::def_id::{DefId, LocalDefIdMap};
 pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
-use crate::intravisit::FnKind;
+use crate::intravisit::{FnKind, VisitorExt};
 
 #[derive(Debug, Copy, Clone, HashStable_Generic)]
 pub struct Lifetime {
@@ -263,14 +264,58 @@ impl<'hir> PathSegment<'hir> {
 /// So, `ConstArg` (specifically, [`ConstArgKind`]) distinguishes between const args
 /// that are [just paths](ConstArgKind::Path) (currently just bare const params)
 /// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`).
+///
+/// The `Unambig` generic parameter represents whether the position this const is from is
+/// unambiguously a const or ambiguous as to whether it is a type or a const. When in an
+/// ambiguous context the parameter is instantiated with an uninhabited type making the
+/// [`ConstArgKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead.
 #[derive(Clone, Copy, Debug, HashStable_Generic)]
-pub struct ConstArg<'hir> {
+#[repr(C)]
+pub struct ConstArg<'hir, Unambig = ()> {
     #[stable_hasher(ignore)]
     pub hir_id: HirId,
-    pub kind: ConstArgKind<'hir>,
+    pub kind: ConstArgKind<'hir, Unambig>,
+}
+
+impl<'hir> ConstArg<'hir, AmbigArg> {
+    /// Converts a `ConstArg` in an ambiguous position to one in an unambiguous position.
+    ///
+    /// Functions accepting an unambiguous consts may expect the [`ConstArgKind::Infer`] variant
+    /// to be used. Care should be taken to separately handle infer consts when calling this
+    /// function as it cannot be handled by downstream code making use of the returned const.
+    ///
+    /// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir visitors, or
+    /// specifically matching on [`GenericArg::Infer`] when handling generic arguments.
+    ///
+    /// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer]
+    pub fn as_unambig_ct(&self) -> &ConstArg<'hir> {
+        // SAFETY: `ConstArg` is `repr(C)` and `ConstArgKind` is marked `repr(u8)` so that the
+        // layout is the same across different ZST type arguments.
+        let ptr = self as *const ConstArg<'hir, AmbigArg> as *const ConstArg<'hir, ()>;
+        unsafe { &*ptr }
+    }
 }
 
 impl<'hir> ConstArg<'hir> {
+    /// Converts a `ConstArg` in an unambigous position to one in an ambiguous position. This is
+    /// fallible as the [`ConstArgKind::Infer`] variant is not present in ambiguous positions.
+    ///
+    /// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if
+    /// infer consts are relevant to you then care should be taken to handle them separately.
+    pub fn try_as_ambig_ct(&self) -> Option<&ConstArg<'hir, AmbigArg>> {
+        if let ConstArgKind::Infer(_, ()) = self.kind {
+            return None;
+        }
+
+        // SAFETY: `ConstArg` is `repr(C)` and `ConstArgKind` is marked `repr(u8)` so that the layout is
+        // the same across different ZST type arguments. We also asserted that the `self` is
+        // not a `ConstArgKind::Infer` so there is no risk of transmuting a `()` to `AmbigArg`.
+        let ptr = self as *const ConstArg<'hir> as *const ConstArg<'hir, AmbigArg>;
+        Some(unsafe { &*ptr })
+    }
+}
+
+impl<'hir, Unambig> ConstArg<'hir, Unambig> {
     pub fn anon_const_hir_id(&self) -> Option<HirId> {
         match self.kind {
             ConstArgKind::Anon(ac) => Some(ac.hir_id),
@@ -282,14 +327,15 @@ impl<'hir> ConstArg<'hir> {
         match self.kind {
             ConstArgKind::Path(path) => path.span(),
             ConstArgKind::Anon(anon) => anon.span,
-            ConstArgKind::Infer(span) => span,
+            ConstArgKind::Infer(span, _) => span,
         }
     }
 }
 
 /// See [`ConstArg`].
 #[derive(Clone, Copy, Debug, HashStable_Generic)]
-pub enum ConstArgKind<'hir> {
+#[repr(u8, C)]
+pub enum ConstArgKind<'hir, Unambig = ()> {
     /// **Note:** Currently this is only used for bare const params
     /// (`N` where `fn foo<const N: usize>(...)`),
     /// not paths to any const (`N` where `const N: usize = ...`).
@@ -297,11 +343,9 @@ pub enum ConstArgKind<'hir> {
     /// However, in the future, we'll be using it for all of those.
     Path(QPath<'hir>),
     Anon(&'hir AnonConst),
-    /// **Note:** Not all inferred consts are represented as
-    /// `ConstArgKind::Infer`. In cases where it is ambiguous whether
-    /// a generic arg is a type or a const, inference variables are
-    /// represented as `GenericArg::Infer` instead.
-    Infer(Span),
+    /// This variant is not always used to represent inference consts, sometimes
+    /// [`GenericArg::Infer`] is used instead.
+    Infer(Span, Unambig),
 }
 
 #[derive(Clone, Copy, Debug, HashStable_Generic)]
@@ -313,19 +357,24 @@ pub struct InferArg {
 
 impl InferArg {
     pub fn to_ty(&self) -> Ty<'static> {
-        Ty { kind: TyKind::Infer, span: self.span, hir_id: self.hir_id }
+        Ty { kind: TyKind::Infer(()), span: self.span, hir_id: self.hir_id }
     }
 }
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub enum GenericArg<'hir> {
     Lifetime(&'hir Lifetime),
-    Type(&'hir Ty<'hir>),
-    Const(&'hir ConstArg<'hir>),
-    /// **Note:** Inference variables are only represented as
-    /// `GenericArg::Infer` in cases where it is ambiguous whether
-    /// a generic arg is a type or a const. Otherwise, inference variables
-    /// are represented as `TyKind::Infer` or `ConstArgKind::Infer`.
+    Type(&'hir Ty<'hir, AmbigArg>),
+    Const(&'hir ConstArg<'hir, AmbigArg>),
+    /// Inference variables in [`GenericArg`] are always represnted by
+    /// `GenericArg::Infer` instead of the `Infer` variants on [`TyKind`] and
+    /// [`ConstArgKind`] as it is not clear until hir ty lowering whether a
+    /// `_` argument is a type or const argument.
+    ///
+    /// However, some builtin types' generic arguments are represented by [`TyKind`]
+    /// without a [`GenericArg`], instead directly storing a [`Ty`] or [`ConstArg`]. In
+    /// such cases they *are* represented by the `Infer` variants on [`TyKind`] and
+    /// [`ConstArgKind`] as it is not ambiguous whether the argument is a type or const.
     Infer(InferArg),
 }
 
@@ -353,7 +402,7 @@ impl GenericArg<'_> {
             GenericArg::Lifetime(_) => "lifetime",
             GenericArg::Type(_) => "type",
             GenericArg::Const(_) => "constant",
-            GenericArg::Infer(_) => "inferred",
+            GenericArg::Infer(_) => "placeholder",
         }
     }
 
@@ -764,11 +813,8 @@ impl<'hir> Generics<'hir> {
                     && let [.., segment] = trait_ref.path.segments
                     && let Some(ret_ty) = segment.args().paren_sugar_output()
                     && let ret_ty = ret_ty.peel_refs()
-                    && let TyKind::TraitObject(
-                        _,
-                        _,
-                        TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar,
-                    ) = ret_ty.kind
+                    && let TyKind::TraitObject(_, tagged_ptr) = ret_ty.kind
+                    && let TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar = tagged_ptr.tag()
                     && ret_ty.span.can_be_used_for_suggestions()
                 {
                     Some(ret_ty.span)
@@ -1239,13 +1285,13 @@ impl fmt::Debug for OwnerNodes<'_> {
             .field("node", &self.nodes[ItemLocalId::ZERO])
             .field(
                 "parents",
-                &self
-                    .nodes
-                    .iter_enumerated()
-                    .map(|(id, parented_node)| {
-                        debug_fn(move |f| write!(f, "({id:?}, {:?})", parented_node.parent))
-                    })
-                    .collect::<Vec<_>>(),
+                &fmt::from_fn(|f| {
+                    f.debug_list()
+                        .entries(self.nodes.iter_enumerated().map(|(id, parented_node)| {
+                            fmt::from_fn(move |f| write!(f, "({id:?}, {:?})", parented_node.parent))
+                        }))
+                        .finish()
+                }),
             )
             .field("bodies", &self.bodies)
             .field("opt_hash_including_bodies", &self.opt_hash_including_bodies)
@@ -2917,15 +2963,84 @@ impl<'hir> AssocItemConstraintKind<'hir> {
     }
 }
 
+/// An uninhabited enum used to make `Infer` variants on [`Ty`] and [`ConstArg`] be
+/// unreachable. Zero-Variant enums are guaranteed to have the same layout as the never
+/// type.
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
-pub struct Ty<'hir> {
+pub enum AmbigArg {}
+
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
+#[repr(C)]
+/// Represents a type in the `HIR`.
+///
+/// The `Unambig` generic parameter represents whether the position this type is from is
+/// unambiguously a type or ambiguous as to whether it is a type or a const. When in an
+/// ambiguous context the parameter is instantiated with an uninhabited type making the
+/// [`TyKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead.
+pub struct Ty<'hir, Unambig = ()> {
     #[stable_hasher(ignore)]
     pub hir_id: HirId,
-    pub kind: TyKind<'hir>,
     pub span: Span,
+    pub kind: TyKind<'hir, Unambig>,
+}
+
+impl<'hir> Ty<'hir, AmbigArg> {
+    /// Converts a `Ty` in an ambiguous position to one in an unambiguous position.
+    ///
+    /// Functions accepting an unambiguous types may expect the [`TyKind::Infer`] variant
+    /// to be used. Care should be taken to separately handle infer types when calling this
+    /// function as it cannot be handled by downstream code making use of the returned ty.
+    ///
+    /// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir visitors, or
+    /// specifically matching on [`GenericArg::Infer`] when handling generic arguments.
+    ///
+    /// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer]
+    pub fn as_unambig_ty(&self) -> &Ty<'hir> {
+        // SAFETY: `Ty` is `repr(C)` and `TyKind` is marked `repr(u8)` so that the layout is
+        // the same across different ZST type arguments.
+        let ptr = self as *const Ty<'hir, AmbigArg> as *const Ty<'hir, ()>;
+        unsafe { &*ptr }
+    }
+}
+
+impl<'hir> Ty<'hir> {
+    /// Converts a `Ty` in an unambigous position to one in an ambiguous position. This is
+    /// fallible as the [`TyKind::Infer`] variant is not present in ambiguous positions.
+    ///
+    /// Functions accepting ambiguous types will not handle the [`TyKind::Infer`] variant, if
+    /// infer types are relevant to you then care should be taken to handle them separately.
+    pub fn try_as_ambig_ty(&self) -> Option<&Ty<'hir, AmbigArg>> {
+        if let TyKind::Infer(()) = self.kind {
+            return None;
+        }
+
+        // SAFETY: `Ty` is `repr(C)` and `TyKind` is marked `repr(u8)` so that the layout is
+        // the same across different ZST type arguments. We also asserted that the `self` is
+        // not a `TyKind::Infer` so there is no risk of transmuting a `()` to `AmbigArg`.
+        let ptr = self as *const Ty<'hir> as *const Ty<'hir, AmbigArg>;
+        Some(unsafe { &*ptr })
+    }
+}
+
+impl<'hir> Ty<'hir, AmbigArg> {
+    pub fn peel_refs(&self) -> &Ty<'hir> {
+        let mut final_ty = self.as_unambig_ty();
+        while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
+            final_ty = ty;
+        }
+        final_ty
+    }
 }
 
 impl<'hir> Ty<'hir> {
+    pub fn peel_refs(&self) -> &Self {
+        let mut final_ty = self;
+        while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
+            final_ty = ty;
+        }
+        final_ty
+    }
+
     /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate.
     pub fn as_generic_param(&self) -> Option<(DefId, Ident)> {
         let TyKind::Path(QPath::Resolved(None, path)) = self.kind else {
@@ -2942,19 +3057,11 @@ impl<'hir> Ty<'hir> {
         }
     }
 
-    pub fn peel_refs(&self) -> &Self {
-        let mut final_ty = self;
-        while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
-            final_ty = ty;
-        }
-        final_ty
-    }
-
     pub fn find_self_aliases(&self) -> Vec<Span> {
         use crate::intravisit::Visitor;
         struct MyVisitor(Vec<Span>);
         impl<'v> Visitor<'v> for MyVisitor {
-            fn visit_ty(&mut self, t: &'v Ty<'v>) {
+            fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) {
                 if matches!(
                     &t.kind,
                     TyKind::Path(QPath::Resolved(_, Path {
@@ -2970,7 +3077,7 @@ impl<'hir> Ty<'hir> {
         }
 
         let mut my_visitor = MyVisitor(vec![]);
-        my_visitor.visit_ty(self);
+        my_visitor.visit_ty_unambig(self);
         my_visitor.0
     }
 
@@ -2979,14 +3086,14 @@ impl<'hir> Ty<'hir> {
     pub fn is_suggestable_infer_ty(&self) -> bool {
         fn are_suggestable_generic_args(generic_args: &[GenericArg<'_>]) -> bool {
             generic_args.iter().any(|arg| match arg {
-                GenericArg::Type(ty) => ty.is_suggestable_infer_ty(),
+                GenericArg::Type(ty) => ty.as_unambig_ty().is_suggestable_infer_ty(),
                 GenericArg::Infer(_) => true,
                 _ => false,
             })
         }
         debug!(?self);
         match &self.kind {
-            TyKind::Infer => true,
+            TyKind::Infer(()) => true,
             TyKind::Slice(ty) => ty.is_suggestable_infer_ty(),
             TyKind::Array(ty, length) => {
                 ty.is_suggestable_infer_ty() || matches!(length.kind, ConstArgKind::Infer(..))
@@ -3200,7 +3307,9 @@ pub enum InferDelegationKind {
 
 /// The various kinds of types recognized by the compiler.
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
-pub enum TyKind<'hir> {
+// SAFETY: `repr(u8)` is required so that `TyKind<()>` and `TyKind<!>` are layout compatible
+#[repr(u8, C)]
+pub enum TyKind<'hir, Unambig = ()> {
     /// Actual type should be inherited from `DefId` signature
     InferDelegation(DefId, InferDelegationKind),
     /// A variable length slice (i.e., `[T]`).
@@ -3230,21 +3339,22 @@ pub enum TyKind<'hir> {
     TraitAscription(GenericBounds<'hir>),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
-    TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
+    ///
+    /// We use pointer tagging to represent a `&'hir Lifetime` and `TraitObjectSyntax` pair
+    /// as otherwise this type being `repr(C)` would result in `TyKind` increasing in size.
+    TraitObject(&'hir [PolyTraitRef<'hir>], TaggedRef<'hir, Lifetime, TraitObjectSyntax>),
     /// Unused for now.
     Typeof(&'hir AnonConst),
-    /// `TyKind::Infer` means the type should be inferred instead of it having been
-    /// specified. This can appear anywhere in a type.
-    ///
-    /// **Note:** Not all inferred types are represented as
-    /// `TyKind::Infer`. In cases where it is ambiguous whether
-    /// a generic arg is a type or a const, inference variables are
-    /// represented as `GenericArg::Infer` instead.
-    Infer,
     /// Placeholder for a type that has failed to be defined.
     Err(rustc_span::ErrorGuaranteed),
     /// Pattern types (`pattern_type!(u32 is 1..)`)
     Pat(&'hir Ty<'hir>, &'hir Pat<'hir>),
+    /// `TyKind::Infer` means the type should be inferred instead of it having been
+    /// specified. This can appear anywhere in a type.
+    ///
+    /// This variant is not always used to represent inference types, sometimes
+    /// [`GenericArg::Infer`] is used instead.
+    Infer(Unambig),
 }
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
@@ -4528,12 +4638,5 @@ mod size_asserts {
     // tidy-alphabetical-end
 }
 
-fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug {
-    struct DebugFn<F>(F);
-    impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Debug for DebugFn<F> {
-        fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-            (self.0)(fmt)
-        }
-    }
-    DebugFn(f)
-}
+#[cfg(test)]
+mod tests;
diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs
new file mode 100644
index 00000000000..300d4435530
--- /dev/null
+++ b/compiler/rustc_hir/src/hir/tests.rs
@@ -0,0 +1,83 @@
+use rustc_span::def_id::DefIndex;
+
+use super::*;
+
+macro_rules! define_tests {
+    ($($name:ident $kind:ident $variant:ident {$($init:tt)*})*) => {$(
+        #[test]
+        fn $name() {
+            let unambig = $kind::$variant::<'_, ()> { $($init)* };
+            let unambig_to_ambig = unsafe { std::mem::transmute::<_, $kind<'_, AmbigArg>>(unambig) };
+
+            assert!(matches!(&unambig_to_ambig, $kind::$variant { $($init)* }));
+
+            let ambig_to_unambig = unsafe { std::mem::transmute::<_, $kind<'_, ()>>(unambig_to_ambig) };
+
+            assert!(matches!(&ambig_to_unambig, $kind::$variant { $($init)* }));
+        }
+    )*};
+}
+
+define_tests! {
+    cast_never TyKind Never {}
+    cast_tup TyKind Tup { 0: &[Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }] }
+    cast_ptr TyKind Ptr { 0: MutTy { ty: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }, mutbl: Mutability::Not }}
+    cast_array TyKind Array {
+        0: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never },
+        1: &ConstArg { hir_id: HirId::INVALID, kind: ConstArgKind::Anon(&AnonConst {
+            hir_id: HirId::INVALID,
+            def_id: LocalDefId { local_def_index: DefIndex::ZERO },
+            body: BodyId { hir_id: HirId::INVALID },
+            span: DUMMY_SP,
+        })}
+    }
+
+    cast_anon ConstArgKind Anon {
+        0: &AnonConst {
+            hir_id: HirId::INVALID,
+            def_id: LocalDefId { local_def_index: DefIndex::ZERO },
+            body: BodyId { hir_id: HirId::INVALID },
+            span: DUMMY_SP,
+        }
+    }
+}
+
+#[test]
+fn trait_object_roundtrips() {
+    trait_object_roundtrips_impl(TraitObjectSyntax::Dyn);
+    trait_object_roundtrips_impl(TraitObjectSyntax::DynStar);
+    trait_object_roundtrips_impl(TraitObjectSyntax::None);
+}
+
+fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) {
+    let unambig = TyKind::TraitObject::<'_, ()>(
+        &[],
+        TaggedRef::new(
+            &const {
+                Lifetime {
+                    hir_id: HirId::INVALID,
+                    ident: Ident::new(sym::name, DUMMY_SP),
+                    res: LifetimeName::Static,
+                }
+            },
+            syntax,
+        ),
+    );
+    let unambig_to_ambig = unsafe { std::mem::transmute::<_, TyKind<'_, AmbigArg>>(unambig) };
+
+    match unambig_to_ambig {
+        TyKind::TraitObject(_, tagged_ref) => {
+            assert!(tagged_ref.tag() == syntax)
+        }
+        _ => panic!("`TyKind::TraitObject` did not roundtrip"),
+    };
+
+    let ambig_to_unambig = unsafe { std::mem::transmute::<_, TyKind<'_, ()>>(unambig_to_ambig) };
+
+    match ambig_to_unambig {
+        TyKind::TraitObject(_, tagged_ref) => {
+            assert!(tagged_ref.tag() == syntax)
+        }
+        _ => panic!("`TyKind::TraitObject` did not roundtrip"),
+    };
+}
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index ef863aca090..b0d80d0f809 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -351,18 +351,48 @@ pub trait Visitor<'v>: Sized {
     fn visit_inline_const(&mut self, c: &'v ConstBlock) -> Self::Result {
         walk_inline_const(self, c)
     }
-    fn visit_const_arg(&mut self, c: &'v ConstArg<'v>) -> Self::Result {
-        walk_const_arg(self, c)
+
+    fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) -> Self::Result {
+        walk_generic_arg(self, generic_arg)
+    }
+
+    /// All types are treated as ambiguous types for the purposes of hir visiting in
+    /// order to ensure that visitors can handle infer vars without it being too error-prone.
+    ///
+    /// See the doc comments on [`Ty`] for an explanation of what it means for a type to be
+    /// ambiguous.
+    ///
+    /// The [`Visitor::visit_infer`] method should be overriden in order to handle infer vars.
+    fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) -> Self::Result {
+        walk_ty(self, t)
     }
+
+    /// All consts are treated as ambiguous consts for the purposes of hir visiting in
+    /// order to ensure that visitors can handle infer vars without it being too error-prone.
+    ///
+    /// See the doc comments on [`ConstArg`] for an explanation of what it means for a const to be
+    /// ambiguous.
+    ///
+    /// The [`Visitor::visit_infer`] method should be overriden in order to handle infer vars.
+    fn visit_const_arg(&mut self, c: &'v ConstArg<'v, AmbigArg>) -> Self::Result {
+        walk_ambig_const_arg(self, c)
+    }
+
+    #[allow(unused_variables)]
+    fn visit_infer(&mut self, inf_id: HirId, inf_span: Span, kind: InferKind<'v>) -> Self::Result {
+        self.visit_id(inf_id)
+    }
+
+    fn visit_lifetime(&mut self, lifetime: &'v Lifetime) -> Self::Result {
+        walk_lifetime(self, lifetime)
+    }
+
     fn visit_expr(&mut self, ex: &'v Expr<'v>) -> Self::Result {
         walk_expr(self, ex)
     }
     fn visit_expr_field(&mut self, field: &'v ExprField<'v>) -> Self::Result {
         walk_expr_field(self, field)
     }
-    fn visit_ty(&mut self, t: &'v Ty<'v>) -> Self::Result {
-        walk_ty(self, t)
-    }
     fn visit_pattern_type_pattern(&mut self, _p: &'v Pat<'v>) {
         // Do nothing. Only a few visitors need to know the details of the pattern type,
         // and they opt into it. All other visitors will just choke on our fake patterns
@@ -444,15 +474,6 @@ pub trait Visitor<'v>: Sized {
     fn visit_label(&mut self, label: &'v Label) -> Self::Result {
         walk_label(self, label)
     }
-    fn visit_infer(&mut self, inf: &'v InferArg) -> Self::Result {
-        walk_inf(self, inf)
-    }
-    fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) -> Self::Result {
-        walk_generic_arg(self, generic_arg)
-    }
-    fn visit_lifetime(&mut self, lifetime: &'v Lifetime) -> Self::Result {
-        walk_lifetime(self, lifetime)
-    }
     // The span is that of the surrounding type/pattern/expr/whatever.
     fn visit_qpath(&mut self, qpath: &'v QPath<'v>, id: HirId, _span: Span) -> Self::Result {
         walk_qpath(self, qpath, id)
@@ -486,6 +507,26 @@ pub trait Visitor<'v>: Sized {
     }
 }
 
+pub trait VisitorExt<'v>: Visitor<'v> {
+    /// Extension trait method to visit types in unambiguous positions, this is not
+    /// directly on the [`Visitor`] trait as this method should never be overridden.
+    ///
+    /// Named `visit_ty_unambig` instead of `visit_unambig_ty` to aid in discovery
+    /// by IDes when `v.visit_ty` is written.
+    fn visit_ty_unambig(&mut self, t: &'v Ty<'v>) -> Self::Result {
+        walk_unambig_ty(self, t)
+    }
+    /// Extension trait method to visit consts in unambiguous positions, this is not
+    /// directly on the [`Visitor`] trait as this method should never be overridden.
+    ///
+    /// Named `visit_const_arg_unambig` instead of `visit_unambig_const_arg` to aid in
+    /// discovery by IDes when `v.visit_const_arg` is written.
+    fn visit_const_arg_unambig(&mut self, c: &'v ConstArg<'v>) -> Self::Result {
+        walk_const_arg(self, c)
+    }
+}
+impl<'v, V: Visitor<'v>> VisitorExt<'v> for V {}
+
 pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> V::Result {
     try_visit!(visitor.visit_id(param.hir_id));
     visitor.visit_pat(param.pat)
@@ -503,12 +544,12 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
         }
         ItemKind::Static(ref typ, _, body) => {
             try_visit!(visitor.visit_id(item.hir_id()));
-            try_visit!(visitor.visit_ty(typ));
+            try_visit!(visitor.visit_ty_unambig(typ));
             try_visit!(visitor.visit_nested_body(body));
         }
         ItemKind::Const(ref typ, ref generics, body) => {
             try_visit!(visitor.visit_id(item.hir_id()));
-            try_visit!(visitor.visit_ty(typ));
+            try_visit!(visitor.visit_ty_unambig(typ));
             try_visit!(visitor.visit_generics(generics));
             try_visit!(visitor.visit_nested_body(body));
         }
@@ -539,7 +580,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
         }
         ItemKind::TyAlias(ref ty, ref generics) => {
             try_visit!(visitor.visit_id(item.hir_id()));
-            try_visit!(visitor.visit_ty(ty));
+            try_visit!(visitor.visit_ty_unambig(ty));
             try_visit!(visitor.visit_generics(generics));
         }
         ItemKind::Enum(ref enum_definition, ref generics) => {
@@ -561,7 +602,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_generics(generics));
             visit_opt!(visitor, visit_trait_ref, of_trait);
-            try_visit!(visitor.visit_ty(self_ty));
+            try_visit!(visitor.visit_ty_unambig(self_ty));
             walk_list!(visitor, visit_impl_item_ref, *items);
         }
         ItemKind::Struct(ref struct_definition, ref generics)
@@ -618,7 +659,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(
             walk_list!(visitor, visit_ident, param_names.iter().copied());
         }
         ForeignItemKind::Static(ref typ, _, _) => {
-            try_visit!(visitor.visit_ty(typ));
+            try_visit!(visitor.visit_ty_unambig(typ));
         }
         ForeignItemKind::Type => (),
     }
@@ -632,7 +673,7 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v LetStmt<'v>) -
     try_visit!(visitor.visit_id(local.hir_id));
     try_visit!(visitor.visit_pat(local.pat));
     visit_opt!(visitor, visit_block, local.els);
-    visit_opt!(visitor, visit_ty, local.ty);
+    visit_opt!(visitor, visit_ty_unambig, local.ty);
     V::Result::output()
 }
 
@@ -735,18 +776,6 @@ pub fn walk_inline_const<'v, V: Visitor<'v>>(
     visitor.visit_nested_body(constant.body)
 }
 
-pub fn walk_const_arg<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    const_arg: &'v ConstArg<'v>,
-) -> V::Result {
-    try_visit!(visitor.visit_id(const_arg.hir_id));
-    match &const_arg.kind {
-        ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, const_arg.hir_id, qpath.span()),
-        ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
-        ConstArgKind::Infer(..) => V::Result::output(),
-    }
-}
-
 pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result {
     try_visit!(visitor.visit_id(expression.hir_id));
     match expression.kind {
@@ -758,7 +787,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
         }
         ExprKind::Repeat(ref element, ref count) => {
             try_visit!(visitor.visit_expr(element));
-            try_visit!(visitor.visit_const_arg(count));
+            try_visit!(visitor.visit_const_arg_unambig(count));
         }
         ExprKind::Struct(ref qpath, fields, ref optional_base) => {
             try_visit!(visitor.visit_qpath(qpath, expression.hir_id, expression.span));
@@ -789,7 +818,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
         }
         ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => {
             try_visit!(visitor.visit_expr(subexpression));
-            try_visit!(visitor.visit_ty(typ));
+            try_visit!(visitor.visit_ty_unambig(typ));
         }
         ExprKind::DropTemps(ref subexpression) => {
             try_visit!(visitor.visit_expr(subexpression));
@@ -798,7 +827,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             // match the visit order in walk_local
             try_visit!(visitor.visit_expr(init));
             try_visit!(visitor.visit_pat(pat));
-            visit_opt!(visitor, visit_ty, ty);
+            visit_opt!(visitor, visit_ty_unambig, ty);
         }
         ExprKind::If(ref cond, ref then, ref else_opt) => {
             try_visit!(visitor.visit_expr(cond));
@@ -866,7 +895,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             try_visit!(visitor.visit_inline_asm(asm, expression.hir_id));
         }
         ExprKind::OffsetOf(ref container, ref fields) => {
-            try_visit!(visitor.visit_ty(container));
+            try_visit!(visitor.visit_ty_unambig(container));
             walk_list!(visitor, visit_ident, fields.iter().copied());
         }
         ExprKind::Yield(ref subexpression, _) => {
@@ -874,7 +903,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
         }
         ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
             try_visit!(visitor.visit_expr(expr));
-            visit_opt!(visitor, visit_ty, ty);
+            visit_opt!(visitor, visit_ty_unambig, ty);
         }
         ExprKind::Lit(_) | ExprKind::Err(_) => {}
     }
@@ -886,20 +915,49 @@ pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField
     try_visit!(visitor.visit_ident(field.ident));
     visitor.visit_expr(field.expr)
 }
+/// We track whether an infer var is from a [`Ty`], [`ConstArg`], or [`GenericArg`] so that
+/// HIR visitors overriding [`Visitor::visit_infer`] can determine what kind of infer is being visited
+pub enum InferKind<'hir> {
+    Ty(&'hir Ty<'hir>),
+    Const(&'hir ConstArg<'hir>),
+    Ambig(&'hir InferArg),
+}
 
-pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Result {
+pub fn walk_generic_arg<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    generic_arg: &'v GenericArg<'v>,
+) -> V::Result {
+    match generic_arg {
+        GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
+        GenericArg::Type(ty) => visitor.visit_ty(ty),
+        GenericArg::Const(ct) => visitor.visit_const_arg(ct),
+        GenericArg::Infer(inf) => visitor.visit_infer(inf.hir_id, inf.span, InferKind::Ambig(inf)),
+    }
+}
+
+pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Result {
+    match typ.try_as_ambig_ty() {
+        Some(ambig_ty) => visitor.visit_ty(ambig_ty),
+        None => {
+            try_visit!(visitor.visit_id(typ.hir_id));
+            visitor.visit_infer(typ.hir_id, typ.span, InferKind::Ty(typ))
+        }
+    }
+}
+
+pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -> V::Result {
     try_visit!(visitor.visit_id(typ.hir_id));
 
     match typ.kind {
-        TyKind::Slice(ref ty) => try_visit!(visitor.visit_ty(ty)),
-        TyKind::Ptr(ref mutable_type) => try_visit!(visitor.visit_ty(mutable_type.ty)),
+        TyKind::Slice(ref ty) => try_visit!(visitor.visit_ty_unambig(ty)),
+        TyKind::Ptr(ref mutable_type) => try_visit!(visitor.visit_ty_unambig(mutable_type.ty)),
         TyKind::Ref(ref lifetime, ref mutable_type) => {
             try_visit!(visitor.visit_lifetime(lifetime));
-            try_visit!(visitor.visit_ty(mutable_type.ty));
+            try_visit!(visitor.visit_ty_unambig(mutable_type.ty));
         }
         TyKind::Never => {}
         TyKind::Tup(tuple_element_types) => {
-            walk_list!(visitor, visit_ty, tuple_element_types);
+            walk_list!(visitor, visit_ty_unambig, tuple_element_types);
         }
         TyKind::BareFn(ref function_declaration) => {
             walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
@@ -907,7 +965,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
         }
         TyKind::UnsafeBinder(ref unsafe_binder) => {
             walk_list!(visitor, visit_generic_param, unsafe_binder.generic_params);
-            try_visit!(visitor.visit_ty(unsafe_binder.inner_ty));
+            try_visit!(visitor.visit_ty_unambig(unsafe_binder.inner_ty));
         }
         TyKind::Path(ref qpath) => {
             try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
@@ -919,25 +977,49 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
             walk_list!(visitor, visit_param_bound, bounds);
         }
         TyKind::Array(ref ty, ref length) => {
-            try_visit!(visitor.visit_ty(ty));
-            try_visit!(visitor.visit_const_arg(length));
+            try_visit!(visitor.visit_ty_unambig(ty));
+            try_visit!(visitor.visit_const_arg_unambig(length));
         }
-        TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
+        TyKind::TraitObject(bounds, ref lifetime) => {
             for bound in bounds {
                 try_visit!(visitor.visit_poly_trait_ref(bound));
             }
             try_visit!(visitor.visit_lifetime(lifetime));
         }
         TyKind::Typeof(ref expression) => try_visit!(visitor.visit_anon_const(expression)),
-        TyKind::Infer | TyKind::InferDelegation(..) | TyKind::Err(_) => {}
+        TyKind::InferDelegation(..) | TyKind::Err(_) => {}
         TyKind::Pat(ty, pat) => {
-            try_visit!(visitor.visit_ty(ty));
+            try_visit!(visitor.visit_ty_unambig(ty));
             try_visit!(visitor.visit_pattern_type_pattern(pat));
         }
     }
     V::Result::output()
 }
 
+pub fn walk_const_arg<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    const_arg: &'v ConstArg<'v>,
+) -> V::Result {
+    match const_arg.try_as_ambig_ct() {
+        Some(ambig_ct) => visitor.visit_const_arg(ambig_ct),
+        None => {
+            try_visit!(visitor.visit_id(const_arg.hir_id));
+            visitor.visit_infer(const_arg.hir_id, const_arg.span(), InferKind::Const(const_arg))
+        }
+    }
+}
+
+pub fn walk_ambig_const_arg<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    const_arg: &'v ConstArg<'v, AmbigArg>,
+) -> V::Result {
+    try_visit!(visitor.visit_id(const_arg.hir_id));
+    match &const_arg.kind {
+        ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, const_arg.hir_id, qpath.span()),
+        ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
+    }
+}
+
 pub fn walk_generic_param<'v, V: Visitor<'v>>(
     visitor: &mut V,
     param: &'v GenericParam<'v>,
@@ -949,9 +1031,11 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
     }
     match param.kind {
         GenericParamKind::Lifetime { .. } => {}
-        GenericParamKind::Type { ref default, .. } => visit_opt!(visitor, visit_ty, default),
+        GenericParamKind::Type { ref default, .. } => {
+            visit_opt!(visitor, visit_ty_unambig, default)
+        }
         GenericParamKind::Const { ref ty, ref default, synthetic: _ } => {
-            try_visit!(visitor.visit_ty(ty));
+            try_visit!(visitor.visit_ty_unambig(ty));
             if let Some(ref default) = default {
                 try_visit!(visitor.visit_const_param_default(param.hir_id, default));
             }
@@ -964,7 +1048,7 @@ pub fn walk_const_param_default<'v, V: Visitor<'v>>(
     visitor: &mut V,
     ct: &'v ConstArg<'v>,
 ) -> V::Result {
-    visitor.visit_const_arg(ct)
+    visitor.visit_const_arg_unambig(ct)
 }
 
 pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) -> V::Result {
@@ -986,7 +1070,7 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
             bound_generic_params,
             origin: _,
         }) => {
-            try_visit!(visitor.visit_ty(bounded_ty));
+            try_visit!(visitor.visit_ty_unambig(bounded_ty));
             walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_generic_param, bound_generic_params);
         }
@@ -999,8 +1083,8 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
             walk_list!(visitor, visit_param_bound, bounds);
         }
         WherePredicateKind::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty }) => {
-            try_visit!(visitor.visit_ty(lhs_ty));
-            try_visit!(visitor.visit_ty(rhs_ty));
+            try_visit!(visitor.visit_ty_unambig(lhs_ty));
+            try_visit!(visitor.visit_ty_unambig(rhs_ty));
         }
     }
     V::Result::output()
@@ -1010,13 +1094,13 @@ pub fn walk_fn_decl<'v, V: Visitor<'v>>(
     visitor: &mut V,
     function_declaration: &'v FnDecl<'v>,
 ) -> V::Result {
-    walk_list!(visitor, visit_ty, function_declaration.inputs);
+    walk_list!(visitor, visit_ty_unambig, function_declaration.inputs);
     visitor.visit_fn_ret_ty(&function_declaration.output)
 }
 
 pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FnRetTy<'v>) -> V::Result {
     if let FnRetTy::Return(output_ty) = *ret_ty {
-        try_visit!(visitor.visit_ty(output_ty));
+        try_visit!(visitor.visit_ty_unambig(output_ty));
     }
     V::Result::output()
 }
@@ -1069,7 +1153,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(
     try_visit!(visitor.visit_id(hir_id));
     match *kind {
         TraitItemKind::Const(ref ty, default) => {
-            try_visit!(visitor.visit_ty(ty));
+            try_visit!(visitor.visit_ty_unambig(ty));
             visit_opt!(visitor, visit_nested_body, default);
         }
         TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => {
@@ -1087,7 +1171,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(
         }
         TraitItemKind::Type(bounds, ref default) => {
             walk_list!(visitor, visit_param_bound, bounds);
-            visit_opt!(visitor, visit_ty, default);
+            visit_opt!(visitor, visit_ty_unambig, default);
         }
     }
     V::Result::output()
@@ -1125,7 +1209,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(
     try_visit!(visitor.visit_id(impl_item.hir_id()));
     match *kind {
         ImplItemKind::Const(ref ty, body) => {
-            try_visit!(visitor.visit_ty(ty));
+            try_visit!(visitor.visit_ty_unambig(ty));
             visitor.visit_nested_body(body)
         }
         ImplItemKind::Fn(ref sig, body_id) => visitor.visit_fn(
@@ -1135,7 +1219,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(
             impl_item.span,
             impl_item.owner_id.def_id,
         ),
-        ImplItemKind::Type(ref ty) => visitor.visit_ty(ty),
+        ImplItemKind::Type(ref ty) => visitor.visit_ty_unambig(ty),
     }
 }
 
@@ -1223,7 +1307,7 @@ pub fn walk_field_def<'v, V: Visitor<'v>>(
     try_visit!(visitor.visit_id(*hir_id));
     try_visit!(visitor.visit_ident(*ident));
     visit_opt!(visitor, visit_anon_const, default);
-    visitor.visit_ty(*ty)
+    visitor.visit_ty_unambig(*ty)
 }
 
 pub fn walk_enum_def<'v, V: Visitor<'v>>(
@@ -1252,18 +1336,6 @@ pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) -> V::Re
     visitor.visit_id(inf.hir_id)
 }
 
-pub fn walk_generic_arg<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    generic_arg: &'v GenericArg<'v>,
-) -> V::Result {
-    match generic_arg {
-        GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
-        GenericArg::Type(ty) => visitor.visit_ty(ty),
-        GenericArg::Const(ct) => visitor.visit_const_arg(ct),
-        GenericArg::Infer(inf) => visitor.visit_infer(inf),
-    }
-}
-
 pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) -> V::Result {
     try_visit!(visitor.visit_id(lifetime.hir_id));
     visitor.visit_ident(lifetime.ident)
@@ -1276,11 +1348,11 @@ pub fn walk_qpath<'v, V: Visitor<'v>>(
 ) -> V::Result {
     match *qpath {
         QPath::Resolved(ref maybe_qself, ref path) => {
-            visit_opt!(visitor, visit_ty, maybe_qself);
+            visit_opt!(visitor, visit_ty_unambig, maybe_qself);
             visitor.visit_path(path, id)
         }
         QPath::TypeRelative(ref qself, ref segment) => {
-            try_visit!(visitor.visit_ty(qself));
+            try_visit!(visitor.visit_ty_unambig(qself));
             visitor.visit_path_segment(segment)
         }
         QPath::LangItem(..) => V::Result::output(),
@@ -1320,8 +1392,8 @@ pub fn walk_assoc_item_constraint<'v, V: Visitor<'v>>(
     try_visit!(visitor.visit_generic_args(constraint.gen_args));
     match constraint.kind {
         AssocItemConstraintKind::Equality { ref term } => match term {
-            Term::Ty(ref ty) => try_visit!(visitor.visit_ty(ty)),
-            Term::Const(ref c) => try_visit!(visitor.visit_const_arg(c)),
+            Term::Ty(ref ty) => try_visit!(visitor.visit_ty_unambig(ty)),
+            Term::Const(ref c) => try_visit!(visitor.visit_const_arg_unambig(c)),
         },
         AssocItemConstraintKind::Bound { bounds } => {
             walk_list!(visitor, visit_param_bound, bounds)
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index fae3b778d7b..02bc069fc5f 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -332,6 +332,10 @@ language_item_table! {
     FallbackSurfaceDrop,     sym::fallback_surface_drop, fallback_surface_drop_fn, Target::Fn,             GenericRequirement::None;
     AllocLayout,             sym::alloc_layout,        alloc_layout,               Target::Struct,         GenericRequirement::None;
 
+    /// For all binary crates without `#![no_main]`, Rust will generate a "main" function.
+    /// The exact name and signature are target-dependent. The "main" function will invoke
+    /// this lang item, passing it the `argc` and `argv` (or null, if those don't exist
+    /// on the current target) as well as the user-defined `fn main` from the binary crate.
     Start,                   sym::start,               start_fn,                   Target::Fn,             GenericRequirement::Exact(1);
 
     EhPersonality,           sym::eh_personality,      eh_personality,             Target::Fn,             GenericRequirement::None;
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 381062b1429..705c167e258 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -6,6 +6,8 @@
 #![allow(internal_features)]
 #![feature(associated_type_defaults)]
 #![feature(closure_track_caller)]
+#![feature(debug_closure_helpers)]
+#![feature(exhaustive_patterns)]
 #![feature(let_chains)]
 #![feature(never_type)]
 #![feature(rustc_attrs)]
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index d7ab6eca84b..be4004f5904 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -353,7 +353,13 @@ hir_analysis_missing_type_params =
         [one] reference
         *[other] references
     } to {$parameters}
-    .note = because of the default `Self` reference, type parameters must be specified on object types
+    .note = because the parameter {$parameterCount ->
+        [one] default references
+        *[other] defaults reference
+    } `Self`, the {$parameterCount ->
+        [one] parameter
+        *[other] parameters
+    } must be specified on the object type
 
 hir_analysis_multiple_relaxed_default_bounds =
     type parameter has more than one relaxed default bound, only one is supported
@@ -489,21 +495,6 @@ hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is hi
 hir_analysis_specialization_trait = implementing `rustc_specialization_trait` traits is unstable
     .help = add `#![feature(min_specialization)]` to the crate attributes to enable
 
-hir_analysis_start_function_parameters = `#[start]` function is not allowed to have type parameters
-    .label = `#[start]` function cannot have type parameters
-
-hir_analysis_start_function_where = `#[start]` function is not allowed to have a `where` clause
-    .label = `#[start]` function cannot have a `where` clause
-
-hir_analysis_start_not_async = `#[start]` function is not allowed to be `async`
-    .label = `#[start]` is not allowed to be `async`
-
-hir_analysis_start_not_target_feature = `#[start]` function is not allowed to have `#[target_feature]`
-    .label = `#[start]` function is not allowed to have `#[target_feature]`
-
-hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]`
-    .label = `#[start]` function is not allowed to be `#[track_caller]`
-
 hir_analysis_static_specialize = cannot specialize on `'static` lifetime
 
 hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index d8e9227a87c..b3eade8c8ae 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -86,7 +86,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
                 if self.infcx.next_trait_solver()
                     && let ty::Alias(..) = ty.kind()
                 {
-                    let (normalized_ty, obligations) = self.structurally_normalize(ty)?;
+                    let (normalized_ty, obligations) = self.structurally_normalize_ty(ty)?;
                     self.state.obligations.extend(obligations);
                     (AutoderefKind::Builtin, normalized_ty)
                 } else {
@@ -166,7 +166,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
         }
 
         let (normalized_ty, obligations) =
-            self.structurally_normalize(Ty::new_projection(tcx, trait_target_def_id, [ty]))?;
+            self.structurally_normalize_ty(Ty::new_projection(tcx, trait_target_def_id, [ty]))?;
         debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
         self.state.obligations.extend(obligations);
 
@@ -174,12 +174,12 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self), ret)]
-    pub fn structurally_normalize(
+    pub fn structurally_normalize_ty(
         &self,
         ty: Ty<'tcx>,
     ) -> Option<(Ty<'tcx>, PredicateObligations<'tcx>)> {
         let ocx = ObligationCtxt::new(self.infcx);
-        let Ok(normalized_ty) = ocx.structurally_normalize(
+        let Ok(normalized_ty) = ocx.structurally_normalize_ty(
             &traits::ObligationCause::misc(self.span, self.body_id),
             self.param_env,
             ty,
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 4a957d5da24..d2ab98bae89 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -6,9 +6,9 @@ use hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
-use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{GenericParamKind, ImplItemKind, intravisit};
+use rustc_hir::intravisit::VisitorExt;
+use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::util;
@@ -1610,7 +1610,7 @@ fn compare_synthetic_generics<'tcx>(
                     struct Visitor(hir::def_id::LocalDefId);
                     impl<'v> intravisit::Visitor<'v> for Visitor {
                         type Result = ControlFlow<Span>;
-                        fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) -> Self::Result {
+                        fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) -> Self::Result {
                             if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind
                                 && let Res::Def(DefKind::TyParam, def_id) = path.res
                                 && def_id == self.0.to_def_id()
@@ -1622,9 +1622,9 @@ fn compare_synthetic_generics<'tcx>(
                         }
                     }
 
-                    let span = input_tys.iter().find_map(|ty| {
-                        intravisit::Visitor::visit_ty(&mut Visitor(impl_def_id), ty).break_value()
-                    })?;
+                    let span = input_tys
+                        .iter()
+                        .find_map(|ty| Visitor(impl_def_id).visit_ty_unambig(ty).break_value())?;
 
                     let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds;
                     let bounds = bounds.first()?.span().to(bounds.last()?.span());
@@ -2362,7 +2362,7 @@ fn try_report_async_mismatch<'tcx>(
             // the right span is a bit difficult.
             return Err(tcx.sess.dcx().emit_err(MethodShouldReturnFuture {
                 span: tcx.def_span(impl_m.def_id),
-                method_name: trait_m.name,
+                method_name: tcx.item_ident(impl_m.def_id),
                 trait_item_span: tcx.hir().span_if_local(trait_m.def_id),
             }));
         }
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index 332ac2fa0c0..25c2f8554b7 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -5,7 +5,7 @@ use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::span_bug;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
+use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_session::config::EntryFnType;
 use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
 use rustc_span::{Span, sym};
@@ -18,7 +18,6 @@ use crate::errors;
 pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) {
     match tcx.entry_fn(()) {
         Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id),
-        Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id),
         _ => {}
     }
 }
@@ -192,83 +191,3 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         });
     }
 }
-
-fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
-    let start_def_id = start_def_id.expect_local();
-    let start_id = tcx.local_def_id_to_hir_id(start_def_id);
-    let start_span = tcx.def_span(start_def_id);
-    let start_t = tcx.type_of(start_def_id).instantiate_identity();
-    match start_t.kind() {
-        ty::FnDef(..) => {
-            if let Node::Item(it) = tcx.hir_node(start_id) {
-                if let hir::ItemKind::Fn { sig, generics, .. } = &it.kind {
-                    let mut error = false;
-                    if !generics.params.is_empty() {
-                        tcx.dcx().emit_err(errors::StartFunctionParameters { span: generics.span });
-                        error = true;
-                    }
-                    if generics.has_where_clause_predicates {
-                        tcx.dcx().emit_err(errors::StartFunctionWhere {
-                            span: generics.where_clause_span,
-                        });
-                        error = true;
-                    }
-                    if sig.header.asyncness.is_async() {
-                        let span = tcx.def_span(it.owner_id);
-                        tcx.dcx().emit_err(errors::StartAsync { span });
-                        error = true;
-                    }
-
-                    let attrs = tcx.hir().attrs(start_id);
-                    for attr in attrs {
-                        if attr.has_name(sym::track_caller) {
-                            tcx.dcx().emit_err(errors::StartTrackCaller {
-                                span: attr.span,
-                                start: start_span,
-                            });
-                            error = true;
-                        }
-                        if attr.has_name(sym::target_feature)
-                            // Calling functions with `#[target_feature]` is
-                            // not unsafe on WASM, see #84988
-                            && !tcx.sess.target.is_like_wasm
-                            && !tcx.sess.opts.actually_rustdoc
-                        {
-                            tcx.dcx().emit_err(errors::StartTargetFeature {
-                                span: attr.span,
-                                start: start_span,
-                            });
-                            error = true;
-                        }
-                    }
-
-                    if error {
-                        return;
-                    }
-                }
-            }
-
-            let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
-                [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
-                tcx.types.isize,
-                false,
-                hir::Safety::Safe,
-                ExternAbi::Rust,
-            ));
-
-            let _ = check_function_signature(
-                tcx,
-                ObligationCause::new(
-                    start_span,
-                    start_def_id,
-                    ObligationCauseCode::StartFunctionType,
-                ),
-                start_def_id.into(),
-                expected_sig,
-            );
-        }
-        _ => {
-            span_bug!(start_span, "start has a non-function type: found `{}`", start_t);
-        }
-    }
-}
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 92b18c80fd8..69b4aa47eba 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -197,7 +197,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
 
 fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) {
     let span = tcx.def_span(impl_item);
-    let ident = tcx.item_name(impl_item);
+    let ident = tcx.item_ident(impl_item);
 
     let err = match tcx.span_of_impl(parent_impl) {
         Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
@@ -297,7 +297,7 @@ fn default_body_is_unstable(
     reason: Option<Symbol>,
     issue: Option<NonZero<u32>>,
 ) {
-    let missing_item_name = tcx.associated_item(item_did).name;
+    let missing_item_name = tcx.item_ident(item_did);
     let (mut some_note, mut none_note, mut reason_str) = (false, false, String::new());
     match reason {
         Some(r) => {
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index dd6adb17c5e..cd19993f937 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -6,10 +6,10 @@ use rustc_abi::ExternAbi;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
-use rustc_hir::ItemKind;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
 use rustc_hir::lang_items::LangItem;
+use rustc_hir::{AmbigArg, ItemKind};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
 use rustc_macros::LintDiagnostic;
@@ -2196,7 +2196,7 @@ impl<'tcx> Visitor<'tcx> for CollectUsageSpans<'_> {
         // Skip the generics. We only care about fields, not where clause/param bounds.
     }
 
-    fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result {
+    fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
         if let hir::TyKind::Path(hir::QPath::Resolved(None, qpath)) = t.kind {
             if let Res::Def(DefKind::TyParam, def_id) = qpath.res
                 && def_id == self.param_def_id
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index b43a808ccdc..27a7c2ea530 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -292,7 +292,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
 
                         res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
                             span,
-                            name: field.name,
+                            name: field.ident(tcx),
                             ty: ty_a,
                         }));
 
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 1be4aa2f63a..4e5f0a3186a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -13,6 +13,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use rustc_session::parse::feature_err;
 use rustc_span::{ErrorGuaranteed, sym};
+use rustc_type_ir::elaborate;
 use tracing::debug;
 
 use crate::errors;
@@ -184,7 +185,7 @@ fn check_object_overlap<'tcx>(
     // check for overlap with the automatic `impl Trait for dyn Trait`
     if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() {
         // This is something like `impl Trait1 for Trait2`. Illegal if
-        // Trait1 is a supertrait of Trait2 or Trait2 is not dyn-compatible.
+        // Trait1 is a supertrait of Trait2 or Trait2 is not dyn compatible.
 
         let component_def_ids = data.iter().flat_map(|predicate| {
             match predicate.skip_binder() {
@@ -205,7 +206,7 @@ fn check_object_overlap<'tcx>(
                 // With the feature enabled, the trait is not implemented automatically,
                 // so this is valid.
             } else {
-                let mut supertrait_def_ids = tcx.supertrait_def_ids(component_def_id);
+                let mut supertrait_def_ids = elaborate::supertrait_def_ids(tcx, component_def_id);
                 if supertrait_def_ids
                     .any(|d| d == trait_def_id && tcx.trait_def(d).implement_via_object)
                 {
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 7d651155781..dbf7a7378f5 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -320,7 +320,7 @@ fn orphan_check<'tcx>(
         }
 
         let ty = if infcx.next_trait_solver() {
-            ocx.structurally_normalize(
+            ocx.structurally_normalize_ty(
                 &cause,
                 ty::ParamEnv::empty(),
                 infcx.resolve_vars_if_possible(ty),
@@ -465,8 +465,8 @@ fn emit_orphan_check_error<'tcx>(
         traits::OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => {
             let mut reported = None;
             for param_def_id in uncovered {
-                let span = tcx.def_ident_span(param_def_id).unwrap();
-                let name = tcx.item_name(param_def_id);
+                let name = tcx.item_ident(param_def_id);
+                let span = name.span;
 
                 reported.get_or_insert(match local_ty {
                     Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal {
@@ -492,7 +492,7 @@ fn lint_uncovered_ty_params<'tcx>(
 
     for param_def_id in uncovered {
         let span = tcx.def_ident_span(param_def_id).unwrap();
-        let name = tcx.item_name(param_def_id);
+        let name = tcx.item_ident(param_def_id);
 
         match local_ty {
             Some(local_type) => tcx.emit_node_span_lint(
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 86c6532c97d..447050ea7d2 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -28,7 +28,7 @@ use rustc_errors::{
 };
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, Visitor, walk_generics};
+use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt, walk_generics};
 use rustc_hir::{self as hir, GenericParamKind, HirId, Node};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::ObligationCause;
@@ -139,29 +139,12 @@ pub(crate) struct HirPlaceholderCollector {
 }
 
 impl<'v> Visitor<'v> for HirPlaceholderCollector {
-    fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
-        if let hir::TyKind::Infer = t.kind {
-            self.spans.push(t.span);
-        }
-        intravisit::walk_ty(self, t)
-    }
-    fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) {
-        match generic_arg {
-            hir::GenericArg::Infer(inf) => {
-                self.spans.push(inf.span);
-                self.may_contain_const_infer = true;
-                intravisit::walk_inf(self, inf);
-            }
-            hir::GenericArg::Type(t) => self.visit_ty(t),
-            _ => {}
-        }
-    }
-    fn visit_const_arg(&mut self, const_arg: &'v hir::ConstArg<'v>) {
-        if let hir::ConstArgKind::Infer(span) = const_arg.kind {
+    fn visit_infer(&mut self, _inf_id: HirId, inf_span: Span, kind: InferKind<'v>) -> Self::Result {
+        self.spans.push(inf_span);
+
+        if let InferKind::Const(_) | InferKind::Ambig(_) = kind {
             self.may_contain_const_infer = true;
-            self.spans.push(span);
         }
-        intravisit::walk_const_arg(self, const_arg)
     }
 }
 
@@ -583,7 +566,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
             .iter()
             .enumerate()
             .map(|(i, a)| {
-                if let hir::TyKind::Infer = a.kind {
+                if let hir::TyKind::Infer(()) = a.kind {
                     if let Some(suggested_ty) =
                         self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
                     {
@@ -593,21 +576,21 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
                 }
 
                 // Only visit the type looking for `_` if we didn't fix the type above
-                visitor.visit_ty(a);
+                visitor.visit_ty_unambig(a);
                 self.lowerer().lower_arg_ty(a, None)
             })
             .collect();
 
         let output_ty = match decl.output {
             hir::FnRetTy::Return(output) => {
-                if let hir::TyKind::Infer = output.kind
+                if let hir::TyKind::Infer(()) = output.kind
                     && let Some(suggested_ty) =
                         self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
                 {
                     infer_replacements.push((output.span, suggested_ty.to_string()));
                     Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string())
                 } else {
-                    visitor.visit_ty(output);
+                    visitor.visit_ty_unambig(output);
                     self.lower_ty(output)
                 }
             }
@@ -945,7 +928,7 @@ fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
                 tcx.dcx().emit_err(errors::EnumDiscriminantOverflowed {
                     span,
                     discr: prev_discr.unwrap().to_string(),
-                    item_name: tcx.item_name(variant.def_id),
+                    item_name: tcx.item_ident(variant.def_id),
                     wrapped_discr: wrapped_discr.to_string(),
                 });
                 None
@@ -1007,11 +990,10 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> {
     }
 
     /// Check if a given field `ident` declared at `field_decl` has been declared elsewhere before.
-    fn check_field_decl(&mut self, ident: Ident, field_decl: FieldDeclSpan) {
+    fn check_field_decl(&mut self, field_name: Ident, field_decl: FieldDeclSpan) {
         use FieldDeclSpan::*;
-        let field_name = ident.name;
-        let ident = ident.normalize_to_macros_2_0();
-        match (field_decl, self.seen_fields.get(&ident).copied()) {
+        let field_name = field_name.normalize_to_macros_2_0();
+        match (field_decl, self.seen_fields.get(&field_name).copied()) {
             (NotNested(span), Some(NotNested(prev_span))) => {
                 self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested {
                     field_name,
@@ -1052,7 +1034,7 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> {
                 });
             }
             (field_decl, None) => {
-                self.seen_fields.insert(ident, field_decl);
+                self.seen_fields.insert(field_name, field_decl);
             }
         }
     }
@@ -1453,7 +1435,7 @@ fn recover_infer_ret_ty<'tcx>(
     });
 
     let mut visitor = HirPlaceholderCollector::default();
-    visitor.visit_ty(infer_ret_ty);
+    visitor.visit_ty_unambig(infer_ret_ty);
 
     let mut diag = bad_placeholder(icx.lowerer(), visitor.spans, "return type");
     let ret_ty = fn_sig.output();
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 075615de522..2ac8acbd3a4 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -3,9 +3,10 @@ use std::ops::ControlFlow;
 
 use hir::intravisit::{self, Visitor};
 use hir::{GenericParamKind, HirId, Node};
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::VisitorExt;
+use rustc_hir::{self as hir, AmbigArg};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint;
 use rustc_span::{Span, Symbol, kw};
@@ -461,7 +462,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
 
     impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
         type Result = ControlFlow<Span>;
-        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow<Span> {
+        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) -> ControlFlow<Span> {
             match ty.kind {
                 hir::TyKind::BareFn(..) => {
                     self.outer_index.shift_in(1);
@@ -539,7 +540,7 @@ impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
         if let GenericParamKind::Const { ty, default: _, synthetic: _ } = p.kind {
             let prev = self.in_param_ty;
             self.in_param_ty = true;
-            let res = self.visit_ty(ty);
+            let res = self.visit_ty_unambig(ty);
             self.in_param_ty = prev;
             res
         } else {
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index e8706d1adfb..72baf5c4b58 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -14,11 +14,11 @@ use rustc_ast::visit::walk_list;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
 use rustc_hir::{
-    GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap, LifetimeName, Node,
+    self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap,
+    LifetimeName, Node,
 };
 use rustc_macros::extension;
 use rustc_middle::hir::nested_filter;
@@ -184,29 +184,11 @@ enum Scope<'a> {
     },
 }
 
-#[derive(Copy, Clone, Debug)]
-enum BinderScopeType {
-    /// Any non-concatenating binder scopes.
-    Normal,
-    /// Within a syntactic trait ref, there may be multiple poly trait refs that
-    /// are nested (under the `associated_type_bounds` feature). The binders of
-    /// the inner poly trait refs are extended from the outer poly trait refs
-    /// and don't increase the late bound depth. If you had
-    /// `T: for<'a>  Foo<Bar: for<'b> Baz<'a, 'b>>`, then the `for<'b>` scope
-    /// would be `Concatenating`. This also used in trait refs in where clauses
-    /// where we have two binders `for<> T: for<> Foo` (I've intentionally left
-    /// out any lifetimes because they aren't needed to show the two scopes).
-    /// The inner `for<>` has a scope of `Concatenating`.
-    Concatenating,
-}
-
-// A helper struct for debugging scopes without printing parent scopes
-struct TruncatedScopeDebug<'a>(&'a Scope<'a>);
-
-impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {
-            Scope::Binder { bound_vars, scope_type, hir_id, where_bound_origin, s: _ } => f
+impl<'a> Scope<'a> {
+    // A helper for debugging scopes without printing parent scopes
+    fn debug_truncated(&'a self) -> impl fmt::Debug + 'a {
+        fmt::from_fn(move |f| match self {
+            Self::Binder { bound_vars, scope_type, hir_id, where_bound_origin, s: _ } => f
                 .debug_struct("Binder")
                 .field("bound_vars", bound_vars)
                 .field("scope_type", scope_type)
@@ -214,38 +196,54 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
                 .field("where_bound_origin", where_bound_origin)
                 .field("s", &"..")
                 .finish(),
-            Scope::Opaque { captures, def_id, s: _ } => f
+            Self::Opaque { captures, def_id, s: _ } => f
                 .debug_struct("Opaque")
                 .field("def_id", def_id)
                 .field("captures", &captures.borrow())
                 .field("s", &"..")
                 .finish(),
-            Scope::Body { id, s: _ } => {
+            Self::Body { id, s: _ } => {
                 f.debug_struct("Body").field("id", id).field("s", &"..").finish()
             }
-            Scope::ObjectLifetimeDefault { lifetime, s: _ } => f
+            Self::ObjectLifetimeDefault { lifetime, s: _ } => f
                 .debug_struct("ObjectLifetimeDefault")
                 .field("lifetime", lifetime)
                 .field("s", &"..")
                 .finish(),
-            Scope::Supertrait { bound_vars, s: _ } => f
+            Self::Supertrait { bound_vars, s: _ } => f
                 .debug_struct("Supertrait")
                 .field("bound_vars", bound_vars)
                 .field("s", &"..")
                 .finish(),
-            Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
-            Scope::LateBoundary { s: _, what, deny_late_regions } => f
+            Self::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
+            Self::LateBoundary { s: _, what, deny_late_regions } => f
                 .debug_struct("LateBoundary")
                 .field("what", what)
                 .field("deny_late_regions", deny_late_regions)
                 .finish(),
-            Scope::Root { opt_parent_item } => {
+            Self::Root { opt_parent_item } => {
                 f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
             }
-        }
+        })
     }
 }
 
+#[derive(Copy, Clone, Debug)]
+enum BinderScopeType {
+    /// Any non-concatenating binder scopes.
+    Normal,
+    /// Within a syntactic trait ref, there may be multiple poly trait refs that
+    /// are nested (under the `associated_type_bounds` feature). The binders of
+    /// the inner poly trait refs are extended from the outer poly trait refs
+    /// and don't increase the late bound depth. If you had
+    /// `T: for<'a>  Foo<Bar: for<'b> Baz<'a, 'b>>`, then the `for<'b>` scope
+    /// would be `Concatenating`. This also used in trait refs in where clauses
+    /// where we have two binders `for<> T: for<> Foo` (I've intentionally left
+    /// out any lifetimes because they aren't needed to show the two scopes).
+    /// The inner `for<>` has a scope of `Concatenating`.
+    Concatenating,
+}
+
 type ScopeRef<'a> = &'a Scope<'a>;
 
 pub(crate) fn provide(providers: &mut Providers) {
@@ -489,15 +487,17 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     struct FindInferInClosureWithBinder;
                     impl<'v> Visitor<'v> for FindInferInClosureWithBinder {
                         type Result = ControlFlow<Span>;
-                        fn visit_ty(&mut self, t: &'v hir::Ty<'v>) -> Self::Result {
-                            if matches!(t.kind, hir::TyKind::Infer) {
-                                ControlFlow::Break(t.span)
-                            } else {
-                                intravisit::walk_ty(self, t)
-                            }
+
+                        fn visit_infer(
+                            &mut self,
+                            _inf_id: HirId,
+                            inf_span: Span,
+                            _kind: InferKind<'v>,
+                        ) -> Self::Result {
+                            ControlFlow::Break(inf_span)
                         }
                     }
-                    FindInferInClosureWithBinder.visit_ty(ty).break_value()
+                    FindInferInClosureWithBinder.visit_ty_unambig(ty).break_value()
                 }
 
                 let infer_in_rt_sp = match fn_decl.output {
@@ -749,7 +749,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
+    fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
         match ty.kind {
             hir::TyKind::BareFn(c) => {
                 let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = c
@@ -810,7 +810,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     intravisit::walk_ty(this, ty);
                 });
             }
-            hir::TyKind::TraitObject(bounds, lifetime, _) => {
+            hir::TyKind::TraitObject(bounds, lifetime) => {
+                let lifetime = lifetime.pointer();
+
                 debug!(?bounds, ?lifetime, "TraitObject");
                 let scope = Scope::TraitRefBoundary { s: self.scope };
                 self.with(scope, |this| {
@@ -827,7 +829,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                         // use the object lifetime defaulting
                         // rules. So e.g., `Box<dyn Debug>` becomes
                         // `Box<dyn Debug + 'static>`.
-                        self.resolve_object_lifetime_default(lifetime)
+                        self.resolve_object_lifetime_default(&*lifetime)
                     }
                     LifetimeName::Infer => {
                         // If the user writes `'_`, we use the *ordinary* elision
@@ -838,7 +840,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     }
                     LifetimeName::Param(..) | LifetimeName::Static => {
                         // If the user wrote an explicit name, use that.
-                        self.visit_lifetime(lifetime);
+                        self.visit_lifetime(&*lifetime);
                     }
                     LifetimeName::Error => {}
                 }
@@ -849,7 +851,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     lifetime: self.map.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
                     s: self.scope,
                 };
-                self.with(scope, |this| this.visit_ty(mt.ty));
+                self.with(scope, |this| this.visit_ty_unambig(mt.ty));
             }
             hir::TyKind::TraitAscription(bounds) => {
                 let scope = Scope::TraitRefBoundary { s: self.scope };
@@ -891,7 +893,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                         this.visit_param_bound(bound);
                     }
                     if let Some(ty) = ty {
-                        this.visit_ty(ty);
+                        this.visit_ty_unambig(ty);
                     }
                 })
             }
@@ -910,7 +912,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             }),
             Type(ty) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| {
                 this.visit_generics(impl_item.generics);
-                this.visit_ty(ty);
+                this.visit_ty_unambig(ty);
             }),
             Const(_, _) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| {
                 intravisit::walk_impl_item(this, impl_item)
@@ -1019,7 +1021,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                 };
                 self.with(scope, |this| {
                     walk_list!(this, visit_generic_param, bound_generic_params);
-                    this.visit_ty(bounded_ty);
+                    this.visit_ty_unambig(bounded_ty);
                     walk_list!(this, visit_param_bound, bounds);
                 })
             }
@@ -1034,8 +1036,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             &hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
                 lhs_ty, rhs_ty, ..
             }) => {
-                self.visit_ty(lhs_ty);
-                self.visit_ty(rhs_ty);
+                self.visit_ty_unambig(lhs_ty);
+                self.visit_ty_unambig(rhs_ty);
             }
         }
     }
@@ -1068,13 +1070,13 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             GenericParamKind::Lifetime { .. } => {}
             GenericParamKind::Type { default, .. } => {
                 if let Some(ty) = default {
-                    self.visit_ty(ty);
+                    self.visit_ty_unambig(ty);
                 }
             }
             GenericParamKind::Const { ty, default, .. } => {
-                self.visit_ty(ty);
+                self.visit_ty_unambig(ty);
                 if let Some(default) = default {
-                    self.visit_const_arg(default);
+                    self.visit_const_arg_unambig(default);
                 }
             }
         }
@@ -1140,7 +1142,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
     {
         let BoundVarContext { tcx, map, .. } = self;
         let mut this = BoundVarContext { tcx: *tcx, map, scope: &wrap_scope };
-        let span = debug_span!("scope", scope = ?TruncatedScopeDebug(this.scope));
+        let span = debug_span!("scope", scope = ?this.scope.debug_truncated());
         {
             let _enter = span.enter();
             f(&mut this);
@@ -1983,15 +1985,15 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
             },
             |this| {
                 for input in inputs {
-                    this.visit_ty(input);
+                    this.visit_ty_unambig(input);
                 }
                 if !in_closure && let Some(output) = output {
-                    this.visit_ty(output);
+                    this.visit_ty_unambig(output);
                 }
             },
         );
         if in_closure && let Some(output) = output {
-            self.visit_ty(output);
+            self.visit_ty_unambig(output);
         }
     }
 
@@ -2309,7 +2311,7 @@ fn is_late_bound_map(
 
     let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx };
     for arg_ty in sig.decl.inputs {
-        constrained_by_input.visit_ty(arg_ty);
+        constrained_by_input.visit_ty_unambig(arg_ty);
     }
 
     let mut appears_in_output =
@@ -2417,7 +2419,7 @@ fn is_late_bound_map(
     }
 
     impl<'v> Visitor<'v> for ConstrainedCollector<'_> {
-        fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+        fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
             match ty.kind {
                 hir::TyKind::Path(
                     hir::QPath::Resolved(Some(_), _) | hir::QPath::TypeRelative(..),
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 51e15767b8c..348d4d708b5 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -1,10 +1,9 @@
 use core::ops::ControlFlow;
 
 use rustc_errors::{Applicability, StashKey, Suggestions};
-use rustc_hir as hir;
-use rustc_hir::HirId;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::Visitor;
+use rustc_hir::intravisit::VisitorExt;
+use rustc_hir::{self as hir, AmbigArg, HirId};
 use rustc_middle::query::plumbing::CyclePlaceholder;
 use rustc_middle::ty::fold::fold_regions;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
@@ -451,7 +450,7 @@ fn infer_placeholder_type<'tcx>(
             let mut visitor = HirPlaceholderCollector::default();
             let node = tcx.hir_node_by_def_id(def_id);
             if let Some(ty) = node.ty() {
-                visitor.visit_ty(ty);
+                visitor.visit_ty_unambig(ty);
             }
             // If we have just one span, let's try to steal a const `_` feature error.
             let try_steal_span = if !tcx.features().generic_arg_infer() && visitor.spans.len() == 1
@@ -525,7 +524,7 @@ pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) ->
     struct HasTait;
     impl<'tcx> Visitor<'tcx> for HasTait {
         type Result = ControlFlow<()>;
-        fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result {
+        fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
             if let hir::TyKind::OpaqueDef(..) = t.kind {
                 ControlFlow::Break(())
             } else {
@@ -533,5 +532,5 @@ pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) ->
             }
         }
     }
-    HasTait.visit_ty(tcx.hir().expect_item(def_id).expect_ty_alias().0).is_break()
+    HasTait.visit_ty_unambig(tcx.hir().expect_item(def_id).expect_ty_alias().0).is_break()
 }
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index d1a1e36c1d5..e2b9fe0f9f7 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -55,7 +55,7 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
     } else {
         let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
             span: tcx.def_span(def_id),
-            name: tcx.item_name(parent_def_id.to_def_id()),
+            name: tcx.item_ident(parent_def_id.to_def_id()),
             what: "impl",
         });
         Ty::new_error(tcx, reported)
@@ -136,7 +136,7 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
         }
         let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
             span: tcx.def_span(def_id),
-            name: tcx.item_name(parent_def_id.to_def_id()),
+            name: tcx.item_ident(parent_def_id.to_def_id()),
             what: match tcx.hir_node(scope) {
                 _ if scope == hir::CRATE_HIR_ID => "module",
                 Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module",
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 00ba1741ed7..1dcea5d0335 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -217,7 +217,7 @@ pub(crate) struct DropImplOnWrongItem {
 pub(crate) enum FieldAlreadyDeclared {
     #[diag(hir_analysis_field_already_declared, code = E0124)]
     NotNested {
-        field_name: Symbol,
+        field_name: Ident,
         #[primary_span]
         #[label]
         span: Span,
@@ -226,7 +226,7 @@ pub(crate) enum FieldAlreadyDeclared {
     },
     #[diag(hir_analysis_field_already_declared_current_nested)]
     CurrentNested {
-        field_name: Symbol,
+        field_name: Ident,
         #[primary_span]
         #[label]
         span: Span,
@@ -239,7 +239,7 @@ pub(crate) enum FieldAlreadyDeclared {
     },
     #[diag(hir_analysis_field_already_declared_previous_nested)]
     PreviousNested {
-        field_name: Symbol,
+        field_name: Ident,
         #[primary_span]
         #[label]
         span: Span,
@@ -252,7 +252,7 @@ pub(crate) enum FieldAlreadyDeclared {
     },
     #[diag(hir_analysis_field_already_declared_both_nested)]
     BothNested {
-        field_name: Symbol,
+        field_name: Ident,
         #[primary_span]
         #[label]
         span: Span,
@@ -418,7 +418,7 @@ pub(crate) struct ValueOfAssociatedStructAlreadySpecified {
 pub(crate) struct UnconstrainedOpaqueType {
     #[primary_span]
     pub span: Span,
-    pub name: Symbol,
+    pub name: Ident,
     pub what: &'static str,
 }
 
@@ -620,48 +620,6 @@ pub(crate) struct TargetFeatureOnMain {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_start_not_track_caller)]
-pub(crate) struct StartTrackCaller {
-    #[primary_span]
-    pub span: Span,
-    #[label]
-    pub start: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_start_not_target_feature)]
-pub(crate) struct StartTargetFeature {
-    #[primary_span]
-    pub span: Span,
-    #[label]
-    pub start: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_start_not_async, code = E0752)]
-pub(crate) struct StartAsync {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_start_function_where, code = E0647)]
-pub(crate) struct StartFunctionWhere {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_start_function_parameters, code = E0132)]
-pub(crate) struct StartFunctionParameters {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(hir_analysis_main_function_return_type_generic, code = E0131)]
 pub(crate) struct MainFunctionReturnTypeGeneric {
     #[primary_span]
@@ -844,7 +802,7 @@ pub(crate) struct EnumDiscriminantOverflowed {
     #[label]
     pub span: Span,
     pub discr: String,
-    pub item_name: Symbol,
+    pub item_name: Ident,
     pub wrapped_discr: String,
 }
 
@@ -935,7 +893,7 @@ pub(crate) enum ImplNotMarkedDefault {
         span: Span,
         #[label(hir_analysis_ok_label)]
         ok_label: Span,
-        ident: Symbol,
+        ident: Ident,
     },
     #[diag(hir_analysis_impl_not_marked_default_err, code = E0520)]
     #[note]
@@ -943,7 +901,7 @@ pub(crate) enum ImplNotMarkedDefault {
         #[primary_span]
         span: Span,
         cname: Symbol,
-        ident: Symbol,
+        ident: Ident,
     },
 }
 
@@ -1019,7 +977,7 @@ pub(crate) struct MissingTraitItemUnstable {
     pub some_note: bool,
     #[note(hir_analysis_none_note)]
     pub none_note: bool,
-    pub missing_item_name: Symbol,
+    pub missing_item_name: Ident,
     pub feature: Symbol,
     pub reason: String,
 }
@@ -1291,7 +1249,7 @@ pub(crate) struct InherentNominal {
 pub(crate) struct DispatchFromDynZST<'a> {
     #[primary_span]
     pub span: Span,
-    pub name: Symbol,
+    pub name: Ident,
     pub ty: Ty<'a>,
 }
 
@@ -1431,7 +1389,7 @@ pub(crate) struct TyParamFirstLocal<'tcx> {
     pub span: Span,
     #[note(hir_analysis_case_note)]
     pub note: (),
-    pub param: Symbol,
+    pub param: Ident,
     pub local_type: Ty<'tcx>,
 }
 
@@ -1443,7 +1401,7 @@ pub(crate) struct TyParamFirstLocalLint<'tcx> {
     pub span: Span,
     #[note(hir_analysis_case_note)]
     pub note: (),
-    pub param: Symbol,
+    pub param: Ident,
     pub local_type: Ty<'tcx>,
 }
 
@@ -1456,7 +1414,7 @@ pub(crate) struct TyParamSome {
     pub span: Span,
     #[note(hir_analysis_only_note)]
     pub note: (),
-    pub param: Symbol,
+    pub param: Ident,
 }
 
 #[derive(LintDiagnostic)]
@@ -1467,7 +1425,7 @@ pub(crate) struct TyParamSomeLint {
     pub span: Span,
     #[note(hir_analysis_only_note)]
     pub note: (),
-    pub param: Symbol,
+    pub param: Ident,
 }
 
 #[derive(Diagnostic)]
@@ -1575,7 +1533,7 @@ pub(crate) struct UnsupportedDelegation<'a> {
 pub(crate) struct MethodShouldReturnFuture {
     #[primary_span]
     pub span: Span,
-    pub method_name: Symbol,
+    pub method_name: Ident,
     #[note]
     pub trait_item_span: Option<Span>,
 }
@@ -1627,7 +1585,7 @@ pub(crate) struct UnconstrainedGenericParameter {
     #[primary_span]
     #[label]
     pub span: Span,
-    pub param_name: Symbol,
+    pub param_name: Ident,
     pub param_def_kind: &'static str,
     #[note(hir_analysis_const_param_note)]
     pub const_param_note: bool,
diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
index 5ae7944f6d5..67407349729 100644
--- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
@@ -495,7 +495,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
                         .iter()
                         .any(|constraint| constraint.ident.name == item.name)
                 })
-                .map(|item| item.name.to_ident_string())
+                .map(|item| self.tcx.item_ident(item.def_id).to_string())
                 .collect()
         } else {
             Vec::default()
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
index 39471931461..4c8f2735b97 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
@@ -201,7 +201,7 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError
     use LayoutError::*;
 
     match layout_err {
-        Unknown(ty) => {
+        TooGeneric(ty) => {
             match abi {
                 ExternAbi::CCmseNonSecureCall => {
                     // prevent double reporting of this error
@@ -211,7 +211,11 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError
                 _ => bug!("invalid ABI: {abi}"),
             }
         }
-        SizeOverflow(..) | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => {
+        Unknown(..)
+        | SizeOverflow(..)
+        | NormalizationFailure(..)
+        | ReferencesError(..)
+        | Cycle(..) => {
             false // not our job to report these
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 71a5727ed6c..e59ff02642c 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -4,13 +4,12 @@ use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
-use rustc_middle::span_bug;
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::{
     self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
     TypeVisitableExt, Upcast,
 };
-use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
 use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations};
 use rustc_type_ir::elaborate::ClauseWithSupertraitSpan;
@@ -30,16 +29,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         &self,
         span: Span,
         hir_id: hir::HirId,
-        hir_trait_bounds: &[hir::PolyTraitRef<'tcx>],
+        hir_bounds: &[hir::PolyTraitRef<'tcx>],
         lifetime: &hir::Lifetime,
         representation: DynKind,
     ) -> Ty<'tcx> {
         let tcx = self.tcx();
+        let dummy_self = tcx.types.trait_object_dummy_self;
 
-        let mut bounds = Bounds::default();
+        let mut user_written_bounds = Bounds::default();
         let mut potential_assoc_types = Vec::new();
-        let dummy_self = self.tcx().types.trait_object_dummy_self;
-        for trait_bound in hir_trait_bounds.iter().rev() {
+        for trait_bound in hir_bounds.iter() {
             if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity {
                 continue;
             }
@@ -53,92 +52,67 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 hir::BoundConstness::Never,
                 hir::BoundPolarity::Positive,
                 dummy_self,
-                &mut bounds,
+                &mut user_written_bounds,
                 PredicateFilter::SelfOnly,
             ) {
                 potential_assoc_types.extend(cur_potential_assoc_types);
             }
         }
 
-        let mut trait_bounds = vec![];
-        let mut projection_bounds = vec![];
-        for (pred, span) in bounds.clauses() {
-            let bound_pred = pred.kind();
-            match bound_pred.skip_binder() {
-                ty::ClauseKind::Trait(trait_pred) => {
-                    assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
-                    trait_bounds.push((bound_pred.rebind(trait_pred.trait_ref), span));
-                }
-                ty::ClauseKind::Projection(proj) => {
-                    projection_bounds.push((bound_pred.rebind(proj), span));
-                }
-                ty::ClauseKind::TypeOutlives(_) => {
-                    // Do nothing, we deal with regions separately
-                }
-                ty::ClauseKind::RegionOutlives(_)
-                | ty::ClauseKind::ConstArgHasType(..)
-                | ty::ClauseKind::WellFormed(_)
-                | ty::ClauseKind::ConstEvaluatable(_)
-                | ty::ClauseKind::HostEffect(..) => {
-                    span_bug!(span, "did not expect {pred} clause in object bounds");
-                }
-            }
-        }
-
-        // Expand trait aliases recursively and check that only one regular (non-auto) trait
-        // is used and no 'maybe' bounds are used.
-        let expanded_traits =
-            traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b)| (a, b)));
-
-        let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
-            expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
+        let (trait_bounds, mut projection_bounds) =
+            traits::expand_trait_aliases(tcx, user_written_bounds.clauses());
+        let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = trait_bounds
+            .into_iter()
+            .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
 
+        // We  don't support empty trait objects.
+        if regular_traits.is_empty() && auto_traits.is_empty() {
+            let guar =
+                self.report_trait_object_with_no_traits_error(span, user_written_bounds.clauses());
+            return Ty::new_error(tcx, guar);
+        }
         // We don't support >1 principal
         if regular_traits.len() > 1 {
             let guar = self.report_trait_object_addition_traits_error(&regular_traits);
             return Ty::new_error(tcx, guar);
         }
-        // We  don't support empty trait objects.
-        if regular_traits.is_empty() && auto_traits.is_empty() {
-            let guar = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
-            return Ty::new_error(tcx, guar);
-        }
         // Don't create a dyn trait if we have errors in the principal.
-        if let Err(guar) = trait_bounds.error_reported() {
+        if let Err(guar) = regular_traits.error_reported() {
             return Ty::new_error(tcx, guar);
         }
 
         // Check that there are no gross dyn-compatibility violations;
         // most importantly, that the supertraits don't contain `Self`,
         // to avoid ICEs.
-        for item in &regular_traits {
-            let violations =
-                hir_ty_lowering_dyn_compatibility_violations(tcx, item.trait_ref().def_id());
-            if !violations.is_empty() {
-                let reported = report_dyn_incompatibility(
-                    tcx,
-                    span,
-                    Some(hir_id),
-                    item.trait_ref().def_id(),
-                    &violations,
-                )
-                .emit();
-                return Ty::new_error(tcx, reported);
+        for (clause, span) in user_written_bounds.clauses() {
+            if let Some(trait_pred) = clause.as_trait_clause() {
+                let violations =
+                    hir_ty_lowering_dyn_compatibility_violations(tcx, trait_pred.def_id());
+                if !violations.is_empty() {
+                    let reported = report_dyn_incompatibility(
+                        tcx,
+                        span,
+                        Some(hir_id),
+                        trait_pred.def_id(),
+                        &violations,
+                    )
+                    .emit();
+                    return Ty::new_error(tcx, reported);
+                }
             }
         }
 
-        let mut needed_associated_types = FxIndexSet::default();
-
-        let principal_span = regular_traits.first().map_or(DUMMY_SP, |info| info.bottom().1);
-        let regular_traits_refs_spans = trait_bounds
-            .into_iter()
-            .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
+        let principal_trait = regular_traits.into_iter().next();
 
-        for (base_trait_ref, original_span) in regular_traits_refs_spans {
-            let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx);
+        let mut needed_associated_types = FxIndexSet::default();
+        if let Some((principal_trait, spans)) = &principal_trait {
+            let pred: ty::Predicate<'tcx> = (*principal_trait).upcast(tcx);
             for ClauseWithSupertraitSpan { pred, supertrait_span } in
-                traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(base_pred, original_span)])
-                    .filter_only_self()
+                traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(
+                    pred,
+                    *spans.last().unwrap(),
+                )])
+                .filter_only_self()
             {
                 debug!("observing object predicate `{pred:?}`");
 
@@ -179,7 +153,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         //     }
                         // ```
                         //
-                        // Here, the user could theoretically write `dyn MyTrait<Output = X>`,
+                        // Here, the user could theoretically write `dyn MyTrait<MyOutput = X>`,
                         // but actually supporting that would "expand" to an infinitely-long type
                         // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
                         //
@@ -188,12 +162,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         // the discussion in #56288 for alternatives.
                         if !references_self {
                             // Include projections defined on supertraits.
-                            projection_bounds.push((pred, original_span));
+                            projection_bounds.push((pred, supertrait_span));
                         }
 
                         self.check_elaborated_projection_mentions_input_lifetimes(
                             pred,
-                            original_span,
+                            *spans.first().unwrap(),
                             supertrait_span,
                         );
                     }
@@ -202,11 +176,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
-        // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where <Self as Trait>::Assoc = Foo`.
-        // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
-        // types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
-        // corresponding `Projection` clause
-        for (projection_bound, span) in &projection_bounds {
+        // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where
+        // <Self as Trait>::Assoc = Foo`. So every `Projection` clause is an
+        // `Assoc = Foo` bound. `needed_associated_types` contains all associated
+        // types that we expect to be provided by the user, so the following loop
+        // removes all the associated types that have a corresponding `Projection`
+        // clause, either from expanding trait aliases or written by the user.
+        for &(projection_bound, span) in &projection_bounds {
             let def_id = projection_bound.item_def_id();
             let trait_ref = tcx.anonymize_bound_vars(
                 projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
@@ -216,17 +192,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 tcx.emit_node_span_lint(
                     UNUSED_ASSOCIATED_TYPE_BOUNDS,
                     hir_id,
-                    *span,
-                    crate::errors::UnusedAssociatedTypeBounds { span: *span },
+                    span,
+                    crate::errors::UnusedAssociatedTypeBounds { span },
                 );
             }
         }
 
         if let Err(guar) = self.check_for_required_assoc_tys(
-            principal_span,
+            principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
             needed_associated_types,
             potential_assoc_types,
-            hir_trait_bounds,
+            hir_bounds,
         ) {
             return Ty::new_error(tcx, guar);
         }
@@ -236,45 +212,42 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering
         // the bounds
         let mut duplicates = FxHashSet::default();
-        auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id()));
-        debug!(?regular_traits);
+        auto_traits.retain(|(trait_pred, _)| duplicates.insert(trait_pred.def_id()));
+
+        debug!(?principal_trait);
         debug!(?auto_traits);
 
         // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
-        let existential_trait_refs = regular_traits.iter().map(|i| {
-            i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
+        let principal_trait_ref = principal_trait.map(|(trait_pred, spans)| {
+            trait_pred.map_bound(|trait_pred| {
+                let trait_ref = trait_pred.trait_ref;
+                assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
                 assert_eq!(trait_ref.self_ty(), dummy_self);
 
+                let span = *spans.first().unwrap();
+
                 // Verify that `dummy_self` did not leak inside default type parameters. This
                 // could not be done at path creation, since we need to see through trait aliases.
                 let mut missing_type_params = vec![];
-                let mut references_self = false;
                 let generics = tcx.generics_of(trait_ref.def_id);
                 let args: Vec<_> = trait_ref
                     .args
                     .iter()
                     .enumerate()
-                    .skip(1) // Remove `Self` for `ExistentialPredicate`.
+                    // Skip `Self`
+                    .skip(1)
                     .map(|(index, arg)| {
-                        if arg == dummy_self.into() {
+                        if arg.walk().any(|arg| arg == dummy_self.into()) {
                             let param = &generics.own_params[index];
                             missing_type_params.push(param.name);
                             Ty::new_misc_error(tcx).into()
-                        } else if arg.walk().any(|arg| arg == dummy_self.into()) {
-                            references_self = true;
-                            let guar = self.dcx().span_delayed_bug(
-                                span,
-                                "trait object trait bounds reference `Self`",
-                            );
-                            replace_dummy_self_with_error(tcx, arg, guar)
                         } else {
                             arg
                         }
                     })
                     .collect();
 
-                let span = i.bottom().1;
-                let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
+                let empty_generic_args = hir_bounds.iter().any(|hir_bound| {
                     hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
                         && hir_bound.span.contains(span)
                 });
@@ -285,26 +258,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     empty_generic_args,
                 );
 
-                if references_self {
-                    let def_id = i.bottom().0.def_id();
-                    struct_span_code_err!(
-                        self.dcx(),
-                        i.bottom().1,
-                        E0038,
-                        "the {} `{}` cannot be made into an object",
-                        tcx.def_descr(def_id),
-                        tcx.item_name(def_id),
-                    )
-                    .with_note(
-                        rustc_middle::traits::DynCompatibilityViolation::SupertraitSelf(
-                            smallvec![],
-                        )
-                        .error_msg(),
-                    )
-                    .emit();
-                }
-
-                ty::ExistentialTraitRef::new(tcx, trait_ref.def_id, args)
+                ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new(
+                    tcx,
+                    trait_ref.def_id,
+                    args,
+                ))
             })
         });
 
@@ -327,21 +285,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     b.projection_term = replace_dummy_self_with_error(tcx, b.projection_term, guar);
                 }
 
-                ty::ExistentialProjection::erase_self_ty(tcx, b)
+                ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
+                    tcx, b,
+                ))
             })
         });
 
-        let regular_trait_predicates = existential_trait_refs
-            .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait));
-        let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| {
-            ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()))
+        let auto_trait_predicates = auto_traits.into_iter().map(|(trait_pred, _)| {
+            assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
+            assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
+
+            ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
         });
+
         // N.b. principal, projections, auto traits
         // FIXME: This is actually wrong with multiple principals in regards to symbol mangling
-        let mut v = regular_trait_predicates
-            .chain(
-                existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)),
-            )
+        let mut v = principal_trait_ref
+            .into_iter()
+            .chain(existential_projections)
             .chain(auto_trait_predicates)
             .collect::<SmallVec<[_; 8]>>();
         v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 7a3d921f00e..36b214b6ae7 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -9,9 +9,10 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_middle::bug;
+use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
 use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
 use rustc_middle::ty::{
-    self, AdtDef, Binder, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeVisitableExt,
+    self, AdtDef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
     suggest_constraining_type_param,
 };
 use rustc_session::parse::feature_err;
@@ -19,8 +20,9 @@ use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
 use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
 use rustc_trait_selection::traits::{
-    FulfillmentError, TraitAliasExpansionInfo, dyn_compatibility_violations_for_assoc_item,
+    FulfillmentError, dyn_compatibility_violations_for_assoc_item,
 };
+use smallvec::SmallVec;
 
 use crate::errors::{
     self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
@@ -720,7 +722,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// emit a generic note suggesting using a `where` clause to constraint instead.
     pub(crate) fn check_for_required_assoc_tys(
         &self,
-        principal_span: Span,
+        spans: SmallVec<[Span; 1]>,
         missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
         potential_assoc_types: Vec<usize>,
         trait_bounds: &[hir::PolyTraitRef<'_>],
@@ -729,6 +731,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             return Ok(());
         }
 
+        let principal_span = *spans.first().unwrap();
+
         let tcx = self.tcx();
         // FIXME: This logic needs some more care w.r.t handling of conflicts
         let missing_assoc_types: Vec<_> = missing_assoc_types
@@ -995,12 +999,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     )),
                 ..
             }) = node
-            && let Some(adt_def) = qself_ty.ty_adt_def()
-            && let [inherent_impl] = tcx.inherent_impls(adt_def.did())
-            && let name = format!("{ident2}_{ident3}")
-            && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx
-                .associated_items(inherent_impl)
-                .filter_by_name_unhygienic(Symbol::intern(&name))
+            && let Some(inherent_impls) = qself_ty
+                .ty_adt_def()
+                .map(|adt_def| tcx.inherent_impls(adt_def.did()))
+                .or_else(|| {
+                    simplify_type(tcx, qself_ty, TreatParams::InstantiateWithInfer)
+                        .map(|simple_ty| tcx.incoherent_impls(simple_ty))
+                })
+            && let name = Symbol::intern(&format!("{ident2}_{ident3}"))
+            && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = inherent_impls
+                .iter()
+                .flat_map(|inherent_impl| {
+                    tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name)
+                })
                 .next()
         {
             Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
@@ -1124,29 +1135,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
     pub fn report_trait_object_addition_traits_error(
         &self,
-        regular_traits: &Vec<TraitAliasExpansionInfo<'_>>,
+        regular_traits: &Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,
     ) -> ErrorGuaranteed {
-        let first_trait = &regular_traits[0];
-        let additional_trait = &regular_traits[1];
+        // we use the last span to point at the traits themselves,
+        // and all other preceding spans are trait alias expansions.
+        let (&first_span, first_alias_spans) = regular_traits[0].1.split_last().unwrap();
+        let (&second_span, second_alias_spans) = regular_traits[1].1.split_last().unwrap();
         let mut err = struct_span_code_err!(
             self.dcx(),
-            additional_trait.bottom().1,
+            *regular_traits[1].1.first().unwrap(),
             E0225,
             "only auto traits can be used as additional traits in a trait object"
         );
-        additional_trait.label_with_exp_info(
-            &mut err,
-            "additional non-auto trait",
-            "additional use",
-        );
-        first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
+        err.span_label(first_span, "first non-auto trait");
+        for &alias_span in first_alias_spans {
+            err.span_label(alias_span, "first non-auto trait comes from this alias");
+        }
+        err.span_label(second_span, "additional non-auto trait");
+        for &alias_span in second_alias_spans {
+            err.span_label(alias_span, "second non-auto trait comes from this alias");
+        }
         err.help(format!(
             "consider creating a new trait with all of these as supertraits and using that \
              trait here instead: `trait NewTrait: {} {{}}`",
             regular_traits
                 .iter()
                 // FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
-                .map(|t| t.trait_ref().print_only_trait_path().to_string())
+                .map(|(pred, _)| pred
+                    .map_bound(|pred| pred.trait_ref)
+                    .print_only_trait_path()
+                    .to_string())
                 .collect::<Vec<_>>()
                 .join(" + "),
         ));
@@ -1161,14 +1179,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     pub fn report_trait_object_with_no_traits_error(
         &self,
         span: Span,
-        trait_bounds: &Vec<(Binder<'tcx, TraitRef<'tcx>>, Span)>,
+        user_written_clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
     ) -> ErrorGuaranteed {
         let tcx = self.tcx();
-        let trait_alias_span = trait_bounds
-            .iter()
-            .map(|&(trait_ref, _)| trait_ref.def_id())
-            .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
-            .map(|trait_ref| tcx.def_span(trait_ref));
+        let trait_alias_span = user_written_clauses
+            .into_iter()
+            .filter_map(|(clause, _)| clause.as_trait_clause())
+            .find(|trait_ref| tcx.is_trait_alias(trait_ref.def_id()))
+            .map(|trait_ref| tcx.def_span(trait_ref.def_id()));
 
         self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span })
     }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
index df00948dd21..fe3dcb35639 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -1,10 +1,9 @@
 use rustc_ast::ast::ParamKindOrd;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, struct_span_code_err};
-use rustc_hir as hir;
-use rustc_hir::GenericArg;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, GenericArg};
 use rustc_middle::ty::{
     self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty,
 };
@@ -41,17 +40,6 @@ fn generic_arg_mismatch_err(
         param.kind.descr(),
     );
 
-    if let GenericParamDefKind::Const { .. } = param.kind {
-        if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. })) {
-            err.help("const arguments cannot yet be inferred with `_`");
-            tcx.disabled_nightly_features(
-                &mut err,
-                param.def_id.as_local().map(|local| tcx.local_def_id_to_hir_id(local)),
-                [(String::new(), sym::generic_arg_infer)],
-            );
-        }
-    }
-
     let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut Diag<'_>| {
         let suggestions = vec![
             (arg.span().shrink_to_lo(), String::from("{ ")),
@@ -270,6 +258,21 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
                             GenericParamDefKind::Const { .. },
                             _,
                         ) => {
+                            if let GenericParamDefKind::Const { .. } = param.kind
+                                && let GenericArg::Infer(inf) = arg
+                                && !tcx.features().generic_arg_infer()
+                            {
+                                rustc_session::parse::feature_err(
+                                    tcx.sess,
+                                    sym::generic_arg_infer,
+                                    inf.span,
+                                    "const arguments cannot yet be inferred with `_`",
+                                )
+                                .emit();
+                            }
+
+                            // We lower to an infer even when the feature gate is not enabled
+                            // as it is useful for diagnostics to be able to see a `ConstKind::Infer`
                             args.push(ctx.provided_kind(&args, param, arg));
                             args_iter.next();
                             params.next();
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index a1f2b8c7594..539c5f6a20a 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -23,9 +23,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     ) -> Option<ErrorGuaranteed> {
         let tcx = self.tcx();
 
-        let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
+        let poly_trait_ref = if let hir::TyKind::TraitObject([poly_trait_ref, ..], tagged_ptr) =
             self_ty.kind
-        else {
+            && let TraitObjectSyntax::None = tagged_ptr.tag()
+        {
+            poly_trait_ref
+        } else {
             return None;
         };
 
@@ -294,7 +297,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let (dyn_str, paren_dyn_str) =
                     if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
 
-                let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind {
+                let sugg = if let hir::TyKind::TraitObject([_, _, ..], _) = self_ty.kind {
                     // There are more than one trait bound, we need surrounding parentheses.
                     vec![
                         (self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()),
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index cb90fff782f..61d5869c19f 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -517,14 +517,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         self.lowerer.lower_lifetime(lt, RegionInferReason::Param(param)).into()
                     }
                     (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
-                        handle_ty_args(has_default, ty)
+                        // We handle the other parts of `Ty` in the match arm below
+                        handle_ty_args(has_default, ty.as_unambig_ty())
                     }
                     (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Infer(inf)) => {
                         handle_ty_args(has_default, &inf.to_ty())
                     }
-                    (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
-                        self.lowerer.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into()
-                    }
+                    (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
+                        .lowerer
+                        // Ambig portions of `ConstArg` are handled in the match arm below
+                        .lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
+                        .into(),
                     (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
                         self.lowerer.ct_infer(Some(param), inf.span).into()
                     }
@@ -2115,7 +2118,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
             ),
             hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon),
-            hir::ConstArgKind::Infer(span) => self.ct_infer(None, span),
+            hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
         }
     }
 
@@ -2311,7 +2314,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     tcx.late_bound_vars(hir_ty.hir_id),
                 ),
             ),
-            hir::TyKind::TraitObject(bounds, lifetime, repr) => {
+            hir::TyKind::TraitObject(bounds, tagged_ptr) => {
+                let lifetime = tagged_ptr.pointer();
+                let repr = tagged_ptr.tag();
+
                 if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
                     // Don't continue with type analysis if the `dyn` keyword is missing
                     // It generates confusing errors, especially if the user meant to use another
@@ -2420,7 +2426,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 Ty::new_array_with_const_len(tcx, self.lower_ty(ty), length)
             }
             hir::TyKind::Typeof(e) => tcx.type_of(e.def_id).instantiate_identity(),
-            hir::TyKind::Infer => {
+            hir::TyKind::Infer(()) => {
                 // Infer also appears as the type of arguments or return
                 // values in an ExprKind::Closure, or as
                 // the type of local variables. Both of these cases are
@@ -2553,7 +2559,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
     pub fn lower_arg_ty(&self, ty: &hir::Ty<'tcx>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
         match ty.kind {
-            hir::TyKind::Infer if let Some(expected_ty) = expected_ty => {
+            hir::TyKind::Infer(()) if let Some(expected_ty) = expected_ty => {
                 self.record_ty(ty.hir_id, expected_ty, ty.span);
                 expected_ty
             }
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index c0fb94d2cb2..f5abcd23440 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -1,6 +1,5 @@
-use rustc_hir as hir;
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{ForeignItem, ForeignItemKind};
+use rustc_hir::intravisit::{self, Visitor, VisitorExt};
+use rustc_hir::{self as hir, AmbigArg, ForeignItem, ForeignItemKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{ObligationCause, WellFormedLoc};
 use rustc_middle::bug;
@@ -68,11 +67,13 @@ fn diagnostic_hir_wf_check<'tcx>(
     }
 
     impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
-        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
+        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
             let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
             let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
-            let tcx_ty = self.icx.lower_ty(ty);
+            // We don't handle infer vars but we wouldn't handle them anyway as we're creating a
+            // fresh `InferCtxt` in this function.
+            let tcx_ty = self.icx.lower_ty(ty.as_unambig_ty());
             // This visitor can walk into binders, resulting in the `tcx_ty` to
             // potentially reference escaping bound variables. We simply erase
             // those here.
@@ -149,7 +150,11 @@ fn diagnostic_hir_wf_check<'tcx>(
                         .iter()
                         .flat_map(|seg| seg.args().args)
                         .filter_map(|arg| {
-                            if let hir::GenericArg::Type(ty) = arg { Some(*ty) } else { None }
+                            if let hir::GenericArg::Type(ty) = arg {
+                                Some(ty.as_unambig_ty())
+                            } else {
+                                None
+                            }
                         })
                         .chain([impl_.self_ty])
                         .collect(),
@@ -196,7 +201,7 @@ fn diagnostic_hir_wf_check<'tcx>(
         }
     };
     for ty in tys {
-        visitor.visit_ty(ty);
+        visitor.visit_ty_unambig(ty);
     }
     visitor.cause
 }
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index 42034736ad6..fd5a7089b4c 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -152,7 +152,7 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
                 {
                     let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
                         span: tcx.def_span(param.def_id),
-                        param_name: param.name,
+                        param_name: tcx.item_ident(param.def_id),
                         param_def_kind: tcx.def_descr(param.def_id),
                         const_param_note: false,
                         const_param_note2: false,
@@ -223,7 +223,7 @@ pub(crate) fn enforce_impl_non_lifetime_params_are_constrained(
             let const_param_note = matches!(param.kind, ty::GenericParamDefKind::Const { .. });
             let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
                 span: tcx.def_span(param.def_id),
-                param_name: param.name,
+                param_name: tcx.item_ident(param.def_id),
                 param_def_kind: tcx.def_descr(param.def_id),
                 const_param_note,
                 const_param_note2: const_param_note,
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index a42a168234f..bc7d4365eee 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -63,6 +63,7 @@ This API is completely unstable and subject to change.
 #![doc(rust_logo)]
 #![feature(assert_matches)]
 #![feature(coroutines)]
+#![feature(debug_closure_helpers)]
 #![feature(if_let_guard)]
 #![feature(iter_from_coroutine)]
 #![feature(iter_intersperse)]
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 3ff6acd79fc..afc0f627f69 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -402,7 +402,8 @@ impl<'a> State<'a> {
                 self.print_bounds("impl", bounds);
             }
             hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
-            hir::TyKind::TraitObject(bounds, lifetime, syntax) => {
+            hir::TyKind::TraitObject(bounds, lifetime) => {
+                let syntax = lifetime.tag();
                 match syntax {
                     ast::TraitObjectSyntax::Dyn => self.word_nbsp("dyn"),
                     ast::TraitObjectSyntax::DynStar => self.word_nbsp("dyn*"),
@@ -421,7 +422,7 @@ impl<'a> State<'a> {
                 if !lifetime.is_elided() {
                     self.nbsp();
                     self.word_space("+");
-                    self.print_lifetime(lifetime);
+                    self.print_lifetime(lifetime.pointer());
                 }
             }
             hir::TyKind::Array(ty, ref length) => {
@@ -441,7 +442,7 @@ impl<'a> State<'a> {
                 self.word("/*ERROR*/");
                 self.pclose();
             }
-            hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => {
+            hir::TyKind::Infer(()) | hir::TyKind::InferDelegation(..) => {
                 self.word("_");
             }
             hir::TyKind::Pat(ty, pat) => {
@@ -1799,8 +1800,8 @@ impl<'a> State<'a> {
                         match generic_arg {
                             GenericArg::Lifetime(lt) if !elide_lifetimes => s.print_lifetime(lt),
                             GenericArg::Lifetime(_) => {}
-                            GenericArg::Type(ty) => s.print_type(ty),
-                            GenericArg::Const(ct) => s.print_const_arg(ct),
+                            GenericArg::Type(ty) => s.print_type(ty.as_unambig_ty()),
+                            GenericArg::Const(ct) => s.print_const_arg(ct.as_unambig_ct()),
                             GenericArg::Infer(_inf) => s.word("_"),
                         }
                     });
@@ -2150,7 +2151,7 @@ impl<'a> State<'a> {
             s.ann.nested(s, Nested::BodyParamPat(body_id, i));
             i += 1;
 
-            if let hir::TyKind::Infer = ty.kind {
+            if let hir::TyKind::Infer(()) = ty.kind {
                 // Print nothing.
             } else {
                 s.word(":");
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 7b07e0ee939..5d00ecbe918 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -45,6 +45,7 @@ use rustc_session::lint;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::{DUMMY_SP, Span, sym};
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_type_ir::elaborate;
 use tracing::{debug, instrument};
 
 use super::FnCtxt;
@@ -923,7 +924,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         let src_auto: FxHashSet<_> = src_tty
                             .auto_traits()
                             .chain(
-                                tcx.supertrait_def_ids(src_principal.def_id())
+                                elaborate::supertrait_def_ids(tcx, src_principal.def_id())
                                     .filter(|def_id| tcx.trait_is_auto(*def_id)),
                             )
                             .collect();
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 6945dbc3216..47abba1cc29 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -461,9 +461,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         // to the target type), since that should be the least
         // confusing.
         let Some(InferOk { value: ty, mut obligations }) = found else {
-            let err = first_error.expect("coerce_borrowed_pointer had no error");
-            debug!("coerce_borrowed_pointer: failed with err = {:?}", err);
-            return Err(err);
+            if let Some(first_error) = first_error {
+                debug!("coerce_borrowed_pointer: failed with err = {:?}", first_error);
+                return Err(first_error);
+            } else {
+                // This may happen in the new trait solver since autoderef requires
+                // the pointee to be structurally normalizable, or else it'll just bail.
+                // So when we have a type like `&<not well formed>`, then we get no
+                // autoderef steps (even though there should be at least one). That means
+                // we get no type mismatches, since the loop above just exits early.
+                return Err(TypeError::Mismatch);
+            }
         };
 
         if ty == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 {
@@ -1124,7 +1132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if self.next_trait_solver()
                     && let ty::Alias(..) = ty.kind()
                 {
-                    ocx.structurally_normalize(&cause, self.param_env, ty)
+                    ocx.structurally_normalize_ty(&cause, self.param_env, ty)
                 } else {
                     Ok(ty)
                 }
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 367e7c6de95..bc076670585 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -851,32 +851,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = pat.kind
 
             // Look for the type corresponding to the argument pattern we have in the argument list.
-            && let Some(ty_sugg) = fn_decl
+            && let Some(ty_ref) = fn_decl
                 .inputs
                 .iter()
-                .filter_map(|ty| {
-                    if ty.span == *ty_span
-                        && let hir::TyKind::Ref(lt, x) = ty.kind
-                    {
-                        // `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
-                        Some((
-                            x.ty.span.shrink_to_lo(),
-                            format!(
-                                "{}mut ",
-                                if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " }
-                            ),
-                        ))
-                    } else {
-                        None
-                    }
+                .filter_map(|ty| match ty.kind {
+                    hir::TyKind::Ref(lt, mut_ty) if ty.span == *ty_span => Some((lt, mut_ty)),
+                    _ => None,
                 })
                 .next()
         {
-            let sugg = vec![
-                ty_sugg,
+            let mut sugg = if ty_ref.1.mutbl.is_mut() {
+                // Leave `&'name mut Ty` and `&mut Ty` as they are (#136028).
+                vec![]
+            } else {
+                // `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
+                vec![(
+                    ty_ref.1.ty.span.shrink_to_lo(),
+                    format!(
+                        "{}mut ",
+                        if ty_ref.0.ident.span.lo() == ty_ref.0.ident.span.hi() { "" } else { " " },
+                    ),
+                )]
+            };
+            sugg.extend([
                 (pat.span.until(ident.span), String::new()),
                 (lhs.span.shrink_to_lo(), "*".to_string()),
-            ];
+            ]);
             // We suggest changing the argument from `mut ident: &Ty` to `ident: &'_ mut Ty` and the
             // assignment from `ident = val;` to `*ident = val;`.
             err.multipart_suggestion_verbose(
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 01fed72d5a2..1c828591bcb 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2349,6 +2349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.report_missing_fields(
                     adt_ty,
                     path_span,
+                    expr.span,
                     remaining_fields,
                     variant,
                     hir_fields,
@@ -2386,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         adt_ty: Ty<'tcx>,
         span: Span,
+        full_span: Span,
         remaining_fields: UnordMap<Ident, (FieldIdx, &ty::FieldDef)>,
         variant: &'tcx ty::VariantDef,
         hir_fields: &'tcx [hir::ExprField<'tcx>],
@@ -2425,6 +2427,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         );
         err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}"));
 
+        if remaining_fields.items().all(|(_, (_, field))| field.value.is_some())
+            && self.tcx.sess.is_nightly_build()
+        {
+            let msg = format!(
+                "all remaining fields have default values, {you_can} use those values with `..`",
+                you_can = if self.tcx.features().default_field_values() {
+                    "you can"
+                } else {
+                    "if you added `#![feature(default_field_values)]` to your crate you could"
+                },
+            );
+            if let Some(hir_field) = hir_fields.last() {
+                err.span_suggestion_verbose(
+                    hir_field.span.shrink_to_hi(),
+                    msg,
+                    ", ..".to_string(),
+                    Applicability::MachineApplicable,
+                );
+            } else if hir_fields.is_empty() {
+                err.span_suggestion_verbose(
+                    span.shrink_to_hi().with_hi(full_span.hi()),
+                    msg,
+                    " { .. }".to_string(),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+
         if let Some(hir_field) = hir_fields.last() {
             self.suggest_fru_from_range_and_emit(hir_field, variant, args, err);
         } else {
@@ -3307,10 +3337,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 })
                 .map(|mut field_path| {
                     field_path.pop();
-                    field_path
-                        .iter()
-                        .map(|id| format!("{}.", id.name.to_ident_string()))
-                        .collect::<String>()
+                    field_path.iter().map(|id| format!("{}.", id)).collect::<String>()
                 })
                 .collect::<Vec<_>>();
             candidate_fields.sort();
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index c128485d93e..1f3f03b9929 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -10,7 +10,7 @@ use rustc_hir as hir;
 use rustc_hir::HirId;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::Visitor;
+use rustc_hir::intravisit::{InferKind, Visitor};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
@@ -641,16 +641,21 @@ impl<'tcx> AnnotateUnitFallbackVisitor<'_, 'tcx> {
 impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
     type Result = ControlFlow<errors::SuggestAnnotation>;
 
-    fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) -> Self::Result {
+    fn visit_infer(
+        &mut self,
+        inf_id: HirId,
+        inf_span: Span,
+        _kind: InferKind<'tcx>,
+    ) -> Self::Result {
         // Try to replace `_` with `()`.
-        if let hir::TyKind::Infer = hir_ty.kind
-            && let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(hir_ty.hir_id)
+        if let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(inf_id)
             && let Some(vid) = self.fcx.root_vid(ty)
             && self.reachable_vids.contains(&vid)
         {
-            return ControlFlow::Break(errors::SuggestAnnotation::Unit(hir_ty.span));
+            return ControlFlow::Break(errors::SuggestAnnotation::Unit(inf_span));
         }
-        hir::intravisit::walk_ty(self, hir_ty)
+
+        ControlFlow::Continue(())
     }
 
     fn visit_qpath(
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index be6d9570e35..8e647ad3c6a 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -6,9 +6,9 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::Visitor;
+use rustc_hir::intravisit::VisitorExt;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{self as hir, ExprKind, GenericArg, HirId, Node, QPath, intravisit};
+use rustc_hir::{self as hir, AmbigArg, ExprKind, GenericArg, HirId, Node, QPath, intravisit};
 use rustc_hir_analysis::hir_ty_lowering::errors::GenericsArgsErrExtend;
 use rustc_hir_analysis::hir_ty_lowering::generics::{
     check_generic_arg_count_for_call, lower_generic_args,
@@ -470,7 +470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         impl<'tcx> intravisit::Visitor<'tcx> for CollectClauses<'_, 'tcx> {
-            fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
+            fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
                 if let Some(clauses) = self.fcx.trait_ascriptions.borrow().get(&ty.hir_id.local_id)
                 {
                     self.clauses.extend(clauses.iter().cloned());
@@ -480,7 +480,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let mut clauses = CollectClauses { clauses: vec![], fcx: self };
-        clauses.visit_ty(hir_ty);
+        clauses.visit_ty_unambig(hir_ty);
         self.tcx.mk_clauses(&clauses.clauses)
     }
 
@@ -1272,14 +1272,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .lower_lifetime(lt, RegionInferReason::Param(param))
                         .into(),
                     (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
-                        self.fcx.lower_ty(ty).raw.into()
-                    }
-                    (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
-                        self.fcx.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into()
+                        // We handle the ambig portions of `Ty` in match arm below
+                        self.fcx.lower_ty(ty.as_unambig_ty()).raw.into()
                     }
                     (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
-                        self.fcx.ty_infer(Some(param), inf.span).into()
+                        self.fcx.lower_ty(&inf.to_ty()).raw.into()
                     }
+                    (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
+                        .fcx
+                        // Ambiguous parts of `ConstArg` are handled in the match arms below
+                        .lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
+                        .into(),
                     (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
                         self.fcx.ct_infer(Some(param), inf.span).into()
                     }
@@ -1433,7 +1436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // in a reentrant borrow, causing an ICE.
             let result = self
                 .at(&self.misc(sp), self.param_env)
-                .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut());
+                .structurally_normalize_ty(ty, &mut **self.fulfillment_cx.borrow_mut());
             match result {
                 Ok(normalized_ty) => normalized_ty,
                 Err(errors) => {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 46eed2db236..8e78fb3e219 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1210,7 +1210,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // - foo((), "current", 42u32, "next")
                             // + foo((), 42u32)
                             {
-                                prev_extra_idx.map_or(true, |prev_extra_idx| {
+                                prev_extra_idx.is_none_or(|prev_extra_idx| {
                                     prev_extra_idx + 1 == arg_idx.index()
                                 })
                             }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 53e055fdeef..928010c03c2 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -185,6 +185,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         rhs_ty: Ty<'tcx>,
         can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool,
     ) -> bool {
+        if lhs_expr.span.in_derive_expansion() || rhs_expr.span.in_derive_expansion() {
+            return false;
+        }
         let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty) else {
             return false;
         };
@@ -1143,7 +1146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.may_coerce(found, ty)
             }
             hir::FnRetTy::DefaultReturn(_) if in_closure => {
-                self.ret_coercion.as_ref().map_or(false, |ret| {
+                self.ret_coercion.as_ref().is_some_and(|ret| {
                     let ret_ty = ret.borrow().expected_ty();
                     self.may_coerce(found, ret_ty)
                 })
@@ -1784,14 +1787,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let results = self.typeck_results.borrow();
         // First, look for a `Clone::clone` call
         if segment.ident.name == sym::clone
-            && results.type_dependent_def_id(expr.hir_id).map_or(
-                false,
-                |did| {
+            && results.type_dependent_def_id(expr.hir_id).is_some_and(|did| {
                     let assoc_item = self.tcx.associated_item(did);
                     assoc_item.container == ty::AssocItemContainer::Trait
                         && assoc_item.container_id(self.tcx) == clone_trait_did
-                },
-            )
+                })
             // If that clone call hasn't already dereferenced the self type (i.e. don't give this
             // diagnostic in cases where we have `(&&T).clone()` and we expect `T`).
             && !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index f4929aae599..54e9e699353 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -122,7 +122,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     format!("generic size {size}")
                 }
             }
-            Err(LayoutError::Unknown(bad)) => {
+            Err(LayoutError::TooGeneric(bad)) => {
                 if *bad == ty {
                     "this type does not have a fixed size".to_owned()
                 } else {
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 9cd9ca040ce..07e013e4afa 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -251,7 +251,8 @@ fn typeck_with_inspect<'tcx>(
 fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Option<Ty<'tcx>> {
     let tcx = fcx.tcx;
     let def_id = fcx.body_id;
-    let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer, span, .. }) = node.ty() {
+    let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty()
+    {
         if let Some(item) = tcx.opt_associated_item(def_id.into())
             && let ty::AssocKind::Const = item.kind
             && let ty::AssocItemContainer::Impl = item.container
@@ -452,7 +453,7 @@ fn report_unexpected_variant_res(
                 );
                 let fields = fields
                     .iter()
-                    .map(|field| format!("{}: _", field.name.to_ident_string()))
+                    .map(|field| format!("{}: _", field.ident(tcx)))
                     .collect::<Vec<_>>()
                     .join(", ");
                 let sugg = format!(" {{ {} }}", fields);
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index f549ced9dc3..880ee83c80a 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -425,14 +425,17 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                         .lower_lifetime(lt, RegionInferReason::Param(param))
                         .into(),
                     (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
-                        self.cfcx.lower_ty(ty).raw.into()
-                    }
-                    (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
-                        self.cfcx.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into()
+                        // We handle the ambig portions of `Ty` in the match arms below
+                        self.cfcx.lower_ty(ty.as_unambig_ty()).raw.into()
                     }
                     (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
-                        self.cfcx.ty_infer(Some(param), inf.span).into()
+                        self.cfcx.lower_ty(&inf.to_ty()).raw.into()
                     }
+                    (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
+                        .cfcx
+                        // We handle the ambig portions of `ConstArg` in the match arms below
+                        .lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
+                        .into(),
                     (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
                         self.cfcx.ct_infer(Some(param), inf.span).into()
                     }
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 116765325a9..b9d1f93bfb8 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1,6 +1,5 @@
 use std::cell::{Cell, RefCell};
 use std::cmp::max;
-use std::iter;
 use std::ops::Deref;
 
 use rustc_data_structures::fx::FxHashSet;
@@ -1009,11 +1008,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
         if self.tcx.is_trait_alias(trait_def_id) {
             // For trait aliases, recursively assume all explicitly named traits are relevant
-            for expansion in traits::expand_trait_aliases(
-                self.tcx,
-                iter::once((ty::Binder::dummy(trait_ref), self.span)),
-            ) {
-                let bound_trait_ref = expansion.trait_ref();
+            for (bound_trait_pred, _) in
+                traits::expand_trait_aliases(self.tcx, [(trait_ref.upcast(self.tcx), self.span)]).0
+            {
+                assert_eq!(bound_trait_pred.polarity(), ty::PredicatePolarity::Positive);
+                let bound_trait_ref = bound_trait_pred.map_bound(|pred| pred.trait_ref);
                 for item in self.impl_or_trait_item(bound_trait_ref.def_id()) {
                     if !self.has_applicable_self(&item) {
                         self.record_static_candidate(CandidateSource::Trait(
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index b3d87ef4ad2..5d4e67d1a0e 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -2714,7 +2714,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .map(|field_path| {
                         field_path
                             .iter()
-                            .map(|id| id.name.to_ident_string())
+                            .map(|id| id.to_string())
                             .collect::<Vec<String>>()
                             .join(".")
                     })
@@ -3761,18 +3761,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                         hir::TraitFn::Required([ident, ..]) => {
                                             ident.name == kw::SelfLower
                                         }
-                                        hir::TraitFn::Provided(body_id) => {
-                                            self.tcx.hir().body(*body_id).params.first().map_or(
-                                                false,
-                                                |param| {
-                                                    matches!(
-                                                        param.pat.kind,
-                                                        hir::PatKind::Binding(_, _, ident, _)
-                                                            if ident.name == kw::SelfLower
-                                                    )
-                                                },
-                                            )
-                                        }
+                                        hir::TraitFn::Provided(body_id) => self
+                                            .tcx
+                                            .hir()
+                                            .body(*body_id)
+                                            .params
+                                            .first()
+                                            .is_some_and(|param| {
+                                                matches!(
+                                                    param.pat.kind,
+                                                    hir::PatKind::Binding(_, _, ident, _)
+                                                        if ident.name == kw::SelfLower
+                                                )
+                                            }),
                                         _ => false,
                                     };
 
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 683cacdff7d..1bf5b19d68d 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -6,9 +6,8 @@ use std::mem;
 
 use rustc_data_structures::unord::ExtendUnord;
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
-use rustc_hir::HirId;
-use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::intravisit::{self, InferKind, Visitor};
+use rustc_hir::{self as hir, AmbigArg, HirId};
 use rustc_middle::span_bug;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
@@ -354,7 +353,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
         self.write_ty_to_typeck_results(l.hir_id, var_ty);
     }
 
-    fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
+    fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
         intravisit::walk_ty(self, hir_ty);
         // If there are type checking errors, Type privacy pass will stop,
         // so we may not get the type from hid_id, see #104513
@@ -364,12 +363,20 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
         }
     }
 
-    fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
-        intravisit::walk_inf(self, inf);
-        // Ignore cases where the inference is a const.
-        if let Some(ty) = self.fcx.node_ty_opt(inf.hir_id) {
-            let ty = self.resolve(ty, &inf.span);
-            self.write_ty_to_typeck_results(inf.hir_id, ty);
+    fn visit_infer(
+        &mut self,
+        inf_id: HirId,
+        inf_span: Span,
+        _kind: InferKind<'cx>,
+    ) -> Self::Result {
+        self.visit_id(inf_id);
+
+        // We don't currently write inference results of const infer vars to
+        // the typeck results as there is not yet any part of the compiler that
+        // needs this information.
+        if let Some(ty) = self.fcx.node_ty_opt(inf_id) {
+            let ty = self.resolve(ty, &inf_span);
+            self.write_ty_to_typeck_results(inf_id, ty);
         }
     }
 }
diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs
index 34f541a8cc6..a3d87f59567 100644
--- a/compiler/rustc_index/src/interval.rs
+++ b/compiler/rustc_index/src/interval.rs
@@ -258,7 +258,7 @@ impl<I: Idx> IntervalSet<I> {
             }
             current = Some(*end);
         }
-        current.map_or(true, |x| x < self.domain as u32)
+        current.is_none_or(|x| x < self.domain as u32)
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs
index 5fc9b679c8a..69ab0e69e21 100644
--- a/compiler/rustc_infer/src/infer/context.rs
+++ b/compiler/rustc_infer/src/infer/context.rs
@@ -114,7 +114,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
         )
     }
 
-    fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
+    fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>>, U>(
         &self,
         value: ty::Binder<'tcx, T>,
         f: impl FnOnce(T) -> U,
diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs
index 7908733e734..061f7e6c22a 100644
--- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs
+++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs
@@ -24,9 +24,9 @@ impl<'tcx> InferCtxt<'tcx> {
     #[instrument(level = "debug", skip(self), ret)]
     pub fn enter_forall_and_leak_universe<T>(&self, binder: ty::Binder<'tcx, T>) -> T
     where
-        T: TypeFoldable<TyCtxt<'tcx>> + Copy,
+        T: TypeFoldable<TyCtxt<'tcx>>,
     {
-        if let Some(inner) = binder.no_bound_vars() {
+        if let Some(inner) = binder.clone().no_bound_vars() {
             return inner;
         }
 
@@ -71,7 +71,7 @@ impl<'tcx> InferCtxt<'tcx> {
     #[instrument(level = "debug", skip(self, f))]
     pub fn enter_forall<T, U>(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U
     where
-        T: TypeFoldable<TyCtxt<'tcx>> + Copy,
+        T: TypeFoldable<TyCtxt<'tcx>>,
     {
         // FIXME: currently we do nothing to prevent placeholders with the new universe being
         // used after exiting `f`. For example region subtyping can result in outlives constraints
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 1456255ea14..2113345eda3 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -1,6 +1,5 @@
 use std::path::PathBuf;
 use std::result;
-use std::sync::Arc;
 
 use rustc_ast::{LitKind, MetaItemKind, token};
 use rustc_codegen_ssa::traits::CodegenBackend;
@@ -309,6 +308,11 @@ pub struct Config {
     pub output_dir: Option<PathBuf>,
     pub output_file: Option<OutFileName>,
     pub ice_file: Option<PathBuf>,
+    /// Load files from sources other than the file system.
+    ///
+    /// Has no uses within this repository, but may be used in the future by
+    /// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for
+    /// running rustc without having to save". (See #102759.)
     pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
     /// The list of fluent resources, used for lints declared with
     /// [`Diagnostic`](rustc_errors::Diagnostic) and [`LintDiagnostic`](rustc_errors::LintDiagnostic).
@@ -337,6 +341,11 @@ pub struct Config {
     pub override_queries: Option<fn(&Session, &mut Providers)>,
 
     /// This is a callback from the driver that is called to create a codegen backend.
+    ///
+    /// Has no uses within this repository, but is used by bjorn3 for "the
+    /// hotswapping branch of cg_clif" for "setting the codegen backend from a
+    /// custom driver where the custom codegen backend has arbitrary data."
+    /// (See #102759.)
     pub make_codegen_backend:
         Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
 
@@ -346,8 +355,7 @@ pub struct Config {
     /// The inner atomic value is set to true when a feature marked as `internal` is
     /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with
     /// internal features are wontfix, and they are usually the cause of the ICEs.
-    /// None signifies that this is not tracked.
-    pub using_internal_features: Arc<std::sync::atomic::AtomicBool>,
+    pub using_internal_features: &'static std::sync::atomic::AtomicBool,
 
     /// All commandline args used to invoke the compiler, with @file args fully expanded.
     /// This will only be used within debug info, e.g. in the pdb file on windows
@@ -383,7 +391,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
     crate::callbacks::setup_callbacks();
 
     let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone());
-    let target = config::build_target_config(&early_dcx, &config.opts, &sysroot);
+    let target = config::build_target_config(&early_dcx, &config.opts.target_triple, &sysroot);
     let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
     let path_mapping = config.opts.file_path_mapping();
     let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target);
@@ -533,7 +541,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
 
 pub fn try_print_query_stack(
     dcx: DiagCtxtHandle<'_>,
-    num_frames: Option<usize>,
+    limit_frames: Option<usize>,
     file: Option<std::fs::File>,
 ) {
     eprintln!("query stack during panic:");
@@ -541,13 +549,13 @@ pub fn try_print_query_stack(
     // Be careful relying on global state here: this code is called from
     // a panic hook, which means that the global `DiagCtxt` may be in a weird
     // state if it was responsible for triggering the panic.
-    let i = ty::tls::with_context_opt(|icx| {
+    let all_frames = ty::tls::with_context_opt(|icx| {
         if let Some(icx) = icx {
             ty::print::with_no_queries!(print_query_stack(
                 QueryCtxt::new(icx.tcx),
                 icx.query,
                 dcx,
-                num_frames,
+                limit_frames,
                 file,
             ))
         } else {
@@ -555,9 +563,14 @@ pub fn try_print_query_stack(
         }
     });
 
-    if num_frames == None || num_frames >= Some(i) {
-        eprintln!("end of query stack");
+    if let Some(limit_frames) = limit_frames
+        && all_frames > limit_frames
+    {
+        eprintln!(
+            "... and {} other queries... use `env RUST_BACKTRACE=1` to see the full query stack",
+            all_frames - limit_frames
+        );
     } else {
-        eprintln!("we're just showing a limited slice of the query stack");
+        eprintln!("end of query stack");
     }
 }
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 07c4b898721..74d02ac2227 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -2,7 +2,7 @@
 use std::collections::{BTreeMap, BTreeSet};
 use std::num::NonZero;
 use std::path::{Path, PathBuf};
-use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
 
 use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_errors::emitter::HumanReadableErrorType;
@@ -42,7 +42,8 @@ where
     let matches = optgroups().parse(args).unwrap();
     let sessopts = build_session_options(&mut early_dcx, &matches);
     let sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone());
-    let target = rustc_session::config::build_target_config(&early_dcx, &sessopts, &sysroot);
+    let target =
+        rustc_session::config::build_target_config(&early_dcx, &sessopts.target_triple, &sysroot);
     let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target);
     let checksum_hash_kind = sessopts.unstable_opts.checksum_hash_algorithm();
     let sm_inputs = Some(SourceMapInputs {
@@ -61,6 +62,8 @@ where
             temps_dir,
         };
 
+        static USING_INTERNAL_FEATURES: AtomicBool = AtomicBool::new(false);
+
         let sess = build_session(
             early_dcx,
             sessopts,
@@ -73,7 +76,7 @@ where
             sysroot,
             "",
             None,
-            Arc::default(),
+            &USING_INTERNAL_FEATURES,
             Default::default(),
         );
         let cfg = parse_cfg(sess.dcx(), matches.opt_strs("cfg"));
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 7522e21d0ef..55c6a122d35 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -69,15 +69,18 @@ lint_builtin_const_no_mangle = const items should never be `#[no_mangle]`
 
 lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function
 lint_builtin_decl_unsafe_method = declaration of an `unsafe` method
-lint_builtin_deprecated_attr_default_suggestion = remove this attribute
 
 lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link}
     .msg_suggestion = {$msg}
     .default_suggestion = remove this attribute
-lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used
 lint_builtin_deref_nullptr = dereferencing a null pointer
     .label = this code causes undefined behavior when executed
 
+lint_builtin_double_negations = use of a double negation
+    .note = the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
+    .note_decrement = use `-= 1` if you meant to decrement the value
+    .add_parens_suggestion = add parentheses for clarity
+
 lint_builtin_ellipsis_inclusive_range_patterns = `...` range patterns are deprecated
     .suggestion = use `..=` for an inclusive range
 
@@ -209,7 +212,9 @@ lint_dangling_pointers_from_temporaries = a dangling pointer will be produced be
     .label_ptr = this pointer will immediately be invalid
     .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
     .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
-    .help = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+    .help_bind = you must make sure that the variable you bind the `{$ty}` to lives at least as long as the pointer returned by the call to `{$callee}`
+    .help_returned = in particular, if this pointer is returned from the current function, binding the `{$ty}` inside the function will not suffice
+    .help_visit = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
     .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
@@ -970,8 +975,7 @@ lint_unused_result = unused result of type `{$ty}`
 
 lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expression or result
 
+lint_uses_power_alignment = repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+
 lint_variant_size_differences =
     enum variant is more than three times larger ({$largest} bytes) than the next largest
-
-lint_wasm_c_abi =
-    older versions of the `wasm-bindgen` crate will be incompatible with future versions of Rust; please update to `wasm-bindgen` v0.2.88
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index fb3cf5afad0..c03de687a33 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -20,7 +20,7 @@ use rustc_abi::BackendRepr;
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::visit::{FnCtxt, FnKind};
 use rustc_ast::{self as ast, *};
-use rustc_ast_pretty::pprust::{self, expr_to_string};
+use rustc_ast_pretty::pprust::expr_to_string;
 use rustc_errors::{Applicability, LintDiagnostic};
 use rustc_feature::{AttributeGate, BuiltinAttribute, GateIssue, Stability, deprecated_attributes};
 use rustc_hir as hir;
@@ -49,16 +49,16 @@ use rustc_trait_selection::traits::{self};
 use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
 use crate::lints::{
     BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
-    BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr,
-    BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
-    BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
-    BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
-    BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, BuiltinMutablesTransmutes,
-    BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed,
-    BuiltinTrivialBounds, BuiltinTypeAliasBounds, BuiltinUngatedAsyncFnTrackCaller,
-    BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub,
-    BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
-    BuiltinWhileTrue, InvalidAsmLabel,
+    BuiltinDeprecatedAttrLinkSuggestion, BuiltinDerefNullptr, BuiltinDoubleNegations,
+    BuiltinDoubleNegationsAddParens, BuiltinEllipsisInclusiveRangePatternsLint,
+    BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote,
+    BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures,
+    BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
+    BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
+    BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasBounds,
+    BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub,
+    BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment,
+    BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel,
 };
 use crate::nonstandard_style::{MethodLateContext, method_context};
 use crate::{
@@ -90,19 +90,11 @@ declare_lint! {
 
 declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
 
-/// Traverse through any amount of parenthesis and return the first non-parens expression.
-fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
-    while let ast::ExprKind::Paren(sub) = &expr.kind {
-        expr = sub;
-    }
-    expr
-}
-
 impl EarlyLintPass for WhileTrue {
     #[inline]
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         if let ast::ExprKind::While(cond, _, label) = &e.kind
-            && let ast::ExprKind::Lit(token_lit) = pierce_parens(cond).kind
+            && let ast::ExprKind::Lit(token_lit) = cond.peel_parens().kind
             && let token::Lit { kind: token::Bool, symbol: kw::True, .. } = token_lit
             && !cond.span.from_expansion()
         {
@@ -848,12 +840,6 @@ impl EarlyLintPass for DeprecatedAttr {
                 return;
             }
         }
-        if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
-            cx.emit_span_lint(DEPRECATED, attr.span, BuiltinDeprecatedAttrUsed {
-                name: pprust::path_to_string(&attr.get_normal_item().path),
-                suggestion: attr.span,
-            });
-        }
     }
 }
 
@@ -1582,6 +1568,58 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
     }
 }
 
+declare_lint! {
+    /// The `double_negations` lint detects expressions of the form `--x`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn main() {
+    ///     let x = 1;
+    ///     let _b = --x;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Negating something twice is usually the same as not negating it at all.
+    /// However, a double negation in Rust can easily be confused with the
+    /// prefix decrement operator that exists in many languages derived from C.
+    /// Use `-(-x)` if you really wanted to negate the value twice.
+    ///
+    /// To decrement a value, use `x -= 1` instead.
+    pub DOUBLE_NEGATIONS,
+    Warn,
+    "detects expressions of the form `--x`"
+}
+
+declare_lint_pass!(
+    /// Lint for expressions of the form `--x` that can be confused with C's
+    /// prefix decrement operator.
+    DoubleNegations => [DOUBLE_NEGATIONS]
+);
+
+impl EarlyLintPass for DoubleNegations {
+    #[inline]
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
+        // only lint on the innermost `--` in a chain of `-` operators,
+        // even if there are 3 or more negations
+        if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind
+            && let ExprKind::Unary(UnOp::Neg, ref inner2) = inner.kind
+            && !matches!(inner2.kind, ExprKind::Unary(UnOp::Neg, _))
+        {
+            cx.emit_span_lint(DOUBLE_NEGATIONS, expr.span, BuiltinDoubleNegations {
+                add_parens: BuiltinDoubleNegationsAddParens {
+                    start_span: inner.span.shrink_to_lo(),
+                    end_span: inner.span.shrink_to_hi(),
+                },
+            });
+        }
+    }
+}
+
 declare_lint_pass!(
     /// Does nothing as a lint pass, but registers some `Lint`s
     /// which are used by other parts of the compiler.
@@ -1600,7 +1638,8 @@ declare_lint_pass!(
         UNSTABLE_FEATURES,
         UNREACHABLE_PUB,
         TYPE_ALIAS_BOUNDS,
-        TRIVIAL_BOUNDS
+        TRIVIAL_BOUNDS,
+        DOUBLE_NEGATIONS
     ]
 );
 
@@ -2657,7 +2696,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
 }
 
 declare_lint! {
-    /// The `deref_nullptr` lint detects when an null pointer is dereferenced,
+    /// The `deref_nullptr` lint detects when a null pointer is dereferenced,
     /// which causes [undefined behavior].
     ///
     /// ### Example
diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs
index 98b717a3070..fd6b3e90ada 100644
--- a/compiler/rustc_lint/src/dangling.rs
+++ b/compiler/rustc_lint/src/dangling.rs
@@ -141,7 +141,7 @@ fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
             expr.hir_id,
             method.ident.span,
             DanglingPointersFromTemporaries {
-                callee: method.ident.name,
+                callee: method.ident,
                 ty,
                 ptr_span: method.ident.span,
                 temporary_span: receiver.span,
diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs
index 6d73715562b..92dbc76a7b5 100644
--- a/compiler/rustc_lint/src/early/diagnostics.rs
+++ b/compiler/rustc_lint/src/early/diagnostics.rs
@@ -430,7 +430,6 @@ pub(super) fn decorate_lint(
         BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => {
             lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)
         }
-        BuiltinLintDiag::WasmCAbi => lints::WasmCAbi.decorate_lint(diag),
         BuiltinLintDiag::IllFormedAttributeInput { suggestions } => {
             lints::IllFormedAttributeInput {
                 num_suggestions: suggestions.len(),
diff --git a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs
index eebb131599a..da6dd8161ee 100644
--- a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs
+++ b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs
@@ -10,19 +10,35 @@ use crate::lints;
 
 const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35;
 
+enum FilterWellKnownNames {
+    Yes,
+    No,
+}
+
 fn sort_and_truncate_possibilities(
     sess: &Session,
     mut possibilities: Vec<Symbol>,
+    filter_well_known_names: FilterWellKnownNames,
 ) -> (Vec<Symbol>, usize) {
+    let possibilities_len = possibilities.len();
+
     let n_possibilities = if sess.opts.unstable_opts.check_cfg_all_expected {
         possibilities.len()
     } else {
+        match filter_well_known_names {
+            FilterWellKnownNames::Yes => {
+                possibilities.retain(|cfg_name| {
+                    !sess.psess.check_config.well_known_names.contains(cfg_name)
+                });
+            }
+            FilterWellKnownNames::No => {}
+        };
         std::cmp::min(possibilities.len(), MAX_CHECK_CFG_NAMES_OR_VALUES)
     };
 
     possibilities.sort_by(|s1, s2| s1.as_str().cmp(s2.as_str()));
 
-    let and_more = possibilities.len().saturating_sub(n_possibilities);
+    let and_more = possibilities_len.saturating_sub(n_possibilities);
     possibilities.truncate(n_possibilities);
     (possibilities, and_more)
 }
@@ -198,8 +214,10 @@ pub(super) fn unexpected_cfg_name(
         } else {
             vec![]
         };
+
+        let (possibilities, and_more) =
+            sort_and_truncate_possibilities(sess, possibilities, FilterWellKnownNames::Yes);
         let expected_names = if !possibilities.is_empty() {
-            let (possibilities, and_more) = sort_and_truncate_possibilities(sess, possibilities);
             let possibilities: Vec<_> =
                 possibilities.into_iter().map(|s| Ident::new(s, name_span)).collect();
             Some(lints::unexpected_cfg_name::ExpectedNames {
@@ -269,8 +287,11 @@ pub(super) fn unexpected_cfg_value(
     // for names as the possibilities could be very long
     let code_sugg = if !possibilities.is_empty() {
         let expected_values = {
-            let (possibilities, and_more) =
-                sort_and_truncate_possibilities(sess, possibilities.clone());
+            let (possibilities, and_more) = sort_and_truncate_possibilities(
+                sess,
+                possibilities.clone(),
+                FilterWellKnownNames::No,
+            );
             lints::unexpected_cfg_value::ExpectedValues {
                 name,
                 have_none_possibility,
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 289e2c9b722..ef79f1301e5 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -57,7 +57,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
         let expect_id = canonicalize_id(expect_id);
 
         if !fulfilled_expectations.contains(&expect_id)
-            && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
+            && tool_filter.is_none_or(|filter| expectation.lint_tool == Some(filter))
         {
             let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale });
             let note = expectation.is_unfulfilled_lint_expectations;
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index 259ea908fc6..b5a6159bd0a 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -9,7 +9,7 @@ use rustc_errors::{
 use rustc_hir::{self as hir, HirIdSet};
 use rustc_macros::LintDiagnostic;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::lint::{FutureIncompatibilityReason, Level};
+use rustc_session::lint::{FutureIncompatibilityReason, LintId};
 use rustc_session::{declare_lint, impl_lint_pass};
 use rustc_span::Span;
 use rustc_span::edition::Edition;
@@ -245,12 +245,12 @@ impl_lint_pass!(
 
 impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
-        if expr.span.edition().at_least_rust_2024() {
-            return;
-        }
-        if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) {
+        if expr.span.edition().at_least_rust_2024()
+            || cx.tcx.lints_that_dont_need_to_run(()).contains(&LintId::of(IF_LET_RESCOPE))
+        {
             return;
         }
+
         if let hir::ExprKind::Loop(block, _label, hir::LoopSource::While, _span) = expr.kind
             && let Some(value) = block.expr
             && let hir::ExprKind::If(cond, _conseq, _alt) = value.kind
@@ -290,7 +290,6 @@ struct IfLetRescopeLint {
     rewrite: Option<IfLetRescopeRewrite>,
 }
 
-// #[derive(Subdiagnostic)]
 struct IfLetRescopeRewrite {
     match_heads: Vec<SingleArmMatchBegin>,
     consequent_heads: Vec<ConsequentRewrite>,
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index b31a4c74787..166ff60f7e1 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -5,8 +5,8 @@ use rustc_ast as ast;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{
-    BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat, PatKind,
-    Path, PathSegment, QPath, Ty, TyKind,
+    AmbigArg, BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat,
+    PatKind, Path, PathSegment, QPath, Ty, TyKind,
 };
 use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -159,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
         }
     }
 
-    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
+    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx, AmbigArg>) {
         match &ty.kind {
             TyKind::Path(QPath::Resolved(_, path)) => {
                 if lint_ty_kind_usage(cx, &path.res) {
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index a4d50c73104..c6d7b839e19 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -8,9 +8,8 @@ use std::cell::Cell;
 
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::join;
-use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, LocalModDefId};
-use rustc_hir::{HirId, intravisit as hir_visit};
+use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::Session;
@@ -214,15 +213,11 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
         })
     }
 
-    fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
+    fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) {
         lint_callback!(self, check_ty, t);
         hir_visit::walk_ty(self, t);
     }
 
-    fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
-        hir_visit::walk_inf(self, inf);
-    }
-
     fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _: Span, n: HirId) {
         if !self.context.only_module {
             self.process_mod(m, n);
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 1465c2cff7b..83a168c3f44 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -181,6 +181,7 @@ early_lint_methods!(
             UnusedDocComment: UnusedDocComment,
             Expr2024: Expr2024,
             Precedence: Precedence,
+            DoubleNegations: DoubleNegations,
         ]
     ]
 );
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index ac995b59caf..09b0e1ed8bd 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -9,6 +9,7 @@ use rustc_errors::{
 };
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::VisitorExt;
 use rustc_hir::{self as hir, MissingLifetimeKind};
 use rustc_macros::{LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::inhabitedness::InhabitedPredicate;
@@ -177,19 +178,6 @@ pub(crate) enum BuiltinDeprecatedAttrLinkSuggestion<'a> {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_builtin_deprecated_attr_used)]
-pub(crate) struct BuiltinDeprecatedAttrUsed {
-    pub name: String,
-    #[suggestion(
-        lint_builtin_deprecated_attr_default_suggestion,
-        style = "short",
-        code = "",
-        applicability = "machine-applicable"
-    )]
-    pub suggestion: Span,
-}
-
-#[derive(LintDiagnostic)]
 #[diag(lint_builtin_unused_doc_comment)]
 pub(crate) struct BuiltinUnusedDocComment<'a> {
     pub kind: &'a str,
@@ -293,7 +281,7 @@ impl<'a> LintDiagnostic<'a, ()> for BuiltinTypeAliasBounds<'_> {
         // avoid doing throwaway work in case the lint ends up getting suppressed.
         let mut collector = ShorthandAssocTyCollector { qselves: Vec::new() };
         if let Some(ty) = self.ty {
-            hir::intravisit::Visitor::visit_ty(&mut collector, ty);
+            collector.visit_ty_unambig(ty);
         }
 
         let affect_object_lifetime_defaults = self
@@ -344,6 +332,24 @@ pub(crate) struct BuiltinTrivialBounds<'a> {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_builtin_double_negations)]
+#[note(lint_note)]
+#[note(lint_note_decrement)]
+pub(crate) struct BuiltinDoubleNegations {
+    #[subdiagnostic]
+    pub add_parens: BuiltinDoubleNegationsAddParens,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(lint_add_parens_suggestion, applicability = "maybe-incorrect")]
+pub(crate) struct BuiltinDoubleNegationsAddParens {
+    #[suggestion_part(code = "(")]
+    pub start_span: Span,
+    #[suggestion_part(code = ")")]
+    pub end_span: Span,
+}
+
+#[derive(LintDiagnostic)]
 pub(crate) enum BuiltinEllipsisInclusiveRangePatternsLint {
     #[diag(lint_builtin_ellipsis_inclusive_range_patterns)]
     Parenthesise {
@@ -1139,10 +1145,12 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> {
 #[derive(LintDiagnostic)]
 #[diag(lint_dangling_pointers_from_temporaries)]
 #[note]
-#[help]
+#[help(lint_help_bind)]
+#[help(lint_help_returned)]
+#[help(lint_help_visit)]
 // FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts
 pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
-    pub callee: Symbol,
+    pub callee: Ident,
     pub ty: Ty<'tcx>,
     #[label(lint_label_ptr)]
     pub ptr_span: Span,
@@ -1343,7 +1351,7 @@ pub(crate) enum NonUpperCaseGlobalSub {
 #[diag(lint_noop_method_call)]
 #[note]
 pub(crate) struct NoopMethodCallDiag<'a> {
-    pub method: Symbol,
+    pub method: Ident,
     pub orig_ty: Ty<'a>,
     pub trait_: Symbol,
     #[suggestion(code = "", applicability = "machine-applicable")]
@@ -1693,6 +1701,10 @@ pub(crate) struct OverflowingLiteral<'a> {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_uses_power_alignment)]
+pub(crate) struct UsesPowerAlignment;
+
+#[derive(LintDiagnostic)]
 #[diag(lint_unused_comparisons)]
 pub(crate) struct UnusedComparisons;
 
@@ -2560,10 +2572,6 @@ pub(crate) struct UnusedCrateDependency {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_wasm_c_abi)]
-pub(crate) struct WasmCAbi;
-
-#[derive(LintDiagnostic)]
 #[diag(lint_ill_formed_attribute_input)]
 pub(crate) struct IllFormedAttributeInput {
     pub num_suggestions: usize,
diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index a1cc3a85109..4e9d793be5b 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -1,6 +1,6 @@
 use rustc_errors::MultiSpan;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::intravisit::{self, Visitor, VisitorExt};
 use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::{declare_lint, impl_lint_pass};
@@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
                 // 1. We collect all the `hir::Path` from the `Self` type and `Trait` ref
                 // of the `impl` definition
                 let mut collector = PathCollector { paths: Vec::new() };
-                collector.visit_ty(&impl_.self_ty);
+                collector.visit_ty_unambig(&impl_.self_ty);
                 if let Some(of_trait) = &impl_.of_trait {
                     collector.visit_trait_ref(of_trait);
                 }
@@ -343,5 +343,5 @@ fn path_span_without_args(path: &Path<'_>) -> Span {
 
 /// Return a "error message-able" ident for the last segment of the `Path`
 fn path_name_to_string(path: &Path<'_>) -> String {
-    path.segments.last().unwrap().ident.name.to_ident_string()
+    path.segments.last().unwrap().ident.to_string()
 }
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index fa519281be5..790ef910b04 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -129,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
                 _ => None,
             };
             cx.emit_span_lint(NOOP_METHOD_CALL, span, NoopMethodCallDiag {
-                method: call.ident.name,
+                method: call.ident,
                 orig_ty,
                 trait_,
                 label: span,
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 53a411e2b87..d347a8c1bc7 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -1,4 +1,4 @@
-use rustc_hir as hir;
+use rustc_hir::{self as hir, AmbigArg};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_macros::{LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::fold::BottomUpFolder;
@@ -67,7 +67,7 @@ declare_lint! {
 declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
 
 impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
-    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx>) {
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
         let hir::TyKind::OpaqueDef(opaque) = &ty.kind else {
             return;
         };
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index 3f264859d48..a1d66047058 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -1,6 +1,5 @@
-use rustc_hir as hir;
 use rustc_hir::def::Res;
-use rustc_hir::{GenericArg, PathSegment, QPath, TyKind};
+use rustc_hir::{self as hir, AmbigArg, GenericArg, PathSegment, QPath, TyKind};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
@@ -22,7 +21,7 @@ declare_tool_lint! {
 declare_lint_pass!(PassByValue => [PASS_BY_VALUE]);
 
 impl<'tcx> LateLintPass<'tcx> for PassByValue {
-    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
+    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
         match &ty.kind {
             TyKind::Ref(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => {
                 if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {
@@ -46,7 +45,7 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<Stri
     if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind {
         match path.res {
             Res::Def(_, def_id) if cx.tcx.has_attr(def_id, sym::rustc_pass_by_value) => {
-                let name = cx.tcx.item_name(def_id).to_ident_string();
+                let name = cx.tcx.item_ident(def_id);
                 let path_segment = path.segments.last().unwrap();
                 return Some(format!("{}{}", name, gen_args(cx, path_segment)));
             }
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index 3a323298bee..8cc8f911d3a 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -25,7 +25,7 @@ macro_rules! late_lint_methods {
             fn check_pat(a: &'tcx rustc_hir::Pat<'tcx>);
             fn check_expr(a: &'tcx rustc_hir::Expr<'tcx>);
             fn check_expr_post(a: &'tcx rustc_hir::Expr<'tcx>);
-            fn check_ty(a: &'tcx rustc_hir::Ty<'tcx>);
+            fn check_ty(a: &'tcx rustc_hir::Ty<'tcx, rustc_hir::AmbigArg>);
             fn check_generic_param(a: &'tcx rustc_hir::GenericParam<'tcx>);
             fn check_generics(a: &'tcx rustc_hir::Generics<'tcx>);
             fn check_poly_trait_ref(a: &'tcx rustc_hir::PolyTraitRef<'tcx>);
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index a9797c3b32a..e0937e43c9a 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -1,4 +1,4 @@
-use rustc_hir::{self as hir, LangItem};
+use rustc_hir::{self as hir, AmbigArg, LangItem};
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::sym;
 
@@ -110,8 +110,10 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
         }
     }
 
-    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
-        let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return };
+    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
+        let hir::TyKind::TraitObject(bounds, _lifetime_and_syntax_pointer) = &ty.kind else {
+            return;
+        };
         for bound in &bounds[..] {
             let def_id = bound.trait_ref.trait_def_id();
             if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) {
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 3bd27a224e7..0060f33888e 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1,14 +1,16 @@
 use std::iter;
 use std::ops::ControlFlow;
 
-use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, Variants, WrappingRange};
+use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, VariantIdx, Variants, WrappingRange};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::DiagMessage;
-use rustc_hir::{Expr, ExprKind, LangItem};
+use rustc_hir::intravisit::VisitorExt;
+use rustc_hir::{AmbigArg, Expr, ExprKind, LangItem};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
 use rustc_middle::ty::{
-    self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    self, Adt, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+    TypeVisitableExt,
 };
 use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
 use rustc_span::def_id::LocalDefId;
@@ -23,7 +25,7 @@ use crate::lints::{
     AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
     AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
     InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons,
-    UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons,
+    UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons, UsesPowerAlignment,
     VariantSizeDifferencesDiag,
 };
 use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
@@ -727,7 +729,60 @@ declare_lint! {
     "proper use of libc types in foreign item definitions"
 }
 
-declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]);
+declare_lint! {
+    /// The `uses_power_alignment` lint detects specific `repr(C)`
+    /// aggregates on AIX.
+    /// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment
+    /// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),
+    /// which can also be set for XLC by `#pragma align(power)` or
+    /// `-qalign=power`. Aggregates with a floating-point type as the
+    /// recursively first field (as in "at offset 0") modify the layout of
+    /// *subsequent* fields of the associated structs to use an alignment value
+    /// where the floating-point type is aligned on a 4-byte boundary.
+    ///
+    /// The power alignment rule for structs needed for C compatibility is
+    /// unimplementable within `repr(C)` in the compiler without building in
+    /// handling of references to packed fields and infectious nested layouts,
+    /// so a warning is produced in these situations.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (fails on non-powerpc64-ibm-aix)
+    /// #[repr(C)]
+    /// pub struct Floats {
+    ///     a: f64,
+    ///     b: u8,
+    ///     c: f64,
+    /// }
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+    ///  --> <source>:5:3
+    ///   |
+    /// 5 |   c: f64,
+    ///   |   ^^^^^^
+    ///   |
+    ///   = note: `#[warn(uses_power_alignment)]` on by default
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// The power alignment rule specifies that the above struct has the
+    /// following alignment:
+    ///  - offset_of!(Floats, a) == 0
+    ///  - offset_of!(Floats, b) == 8
+    ///  - offset_of!(Floats, c) == 12
+    /// However, rust currently aligns `c` at offset_of!(Floats, c) == 16.
+    /// Thus, a warning should be produced for the above struct in this case.
+    USES_POWER_ALIGNMENT,
+    Warn,
+    "Structs do not follow the power alignment rule under repr(C)"
+}
+
+declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS, USES_POWER_ALIGNMENT]);
 
 #[derive(Clone, Copy)]
 pub(crate) enum CItemKind {
@@ -1472,7 +1527,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         }
 
         impl<'a, 'b, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'a, 'b, 'tcx> {
-            fn visit_ty(&mut self, ty: &'_ hir::Ty<'_>) {
+            fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) {
                 debug!(?ty);
                 if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind
                     && !self.visitor.is_internal_abi(*abi)
@@ -1500,7 +1555,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
         let mut visitor = FnPtrFinder { visitor: self, spans: Vec::new(), tys: Vec::new() };
         ty.visit_with(&mut visitor);
-        hir::intravisit::Visitor::visit_ty(&mut visitor, hir_ty);
+        visitor.visit_ty_unambig(hir_ty);
 
         iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)).collect()
     }
@@ -1539,6 +1594,71 @@ impl ImproperCTypesDefinitions {
             vis.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, true, false);
         }
     }
+
+    fn check_arg_for_power_alignment<'tcx>(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> bool {
+        // Structs (under repr(C)) follow the power alignment rule if:
+        //   - the first field of the struct is a floating-point type that
+        //     is greater than 4-bytes, or
+        //   - the first field of the struct is an aggregate whose
+        //     recursively first field is a floating-point type greater than
+        //     4 bytes.
+        if cx.tcx.sess.target.os != "aix" {
+            return false;
+        }
+        if ty.is_floating_point() && ty.primitive_size(cx.tcx).bytes() > 4 {
+            return true;
+        } else if let Adt(adt_def, _) = ty.kind()
+            && adt_def.is_struct()
+        {
+            let struct_variant = adt_def.variant(VariantIdx::ZERO);
+            // Within a nested struct, all fields are examined to correctly
+            // report if any fields after the nested struct within the
+            // original struct are misaligned.
+            for struct_field in &struct_variant.fields {
+                let field_ty = cx.tcx.type_of(struct_field.did).instantiate_identity();
+                if self.check_arg_for_power_alignment(cx, field_ty) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    fn check_struct_for_power_alignment<'tcx>(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        item: &'tcx hir::Item<'tcx>,
+    ) {
+        let adt_def = cx.tcx.adt_def(item.owner_id.to_def_id());
+        if adt_def.repr().c()
+            && !adt_def.repr().packed()
+            && cx.tcx.sess.target.os == "aix"
+            && !adt_def.all_fields().next().is_none()
+        {
+            let struct_variant_data = item.expect_struct().0;
+            for (index, ..) in struct_variant_data.fields().iter().enumerate() {
+                // Struct fields (after the first field) are checked for the
+                // power alignment rule, as fields after the first are likely
+                // to be the fields that are misaligned.
+                if index != 0 {
+                    let first_field_def = struct_variant_data.fields()[index];
+                    let def_id = first_field_def.def_id;
+                    let ty = cx.tcx.type_of(def_id).instantiate_identity();
+                    if self.check_arg_for_power_alignment(cx, ty) {
+                        cx.emit_span_lint(
+                            USES_POWER_ALIGNMENT,
+                            first_field_def.span,
+                            UsesPowerAlignment,
+                        );
+                    }
+                }
+            }
+        }
+    }
 }
 
 /// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
@@ -1562,8 +1682,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
             }
             // See `check_fn`..
             hir::ItemKind::Fn { .. } => {}
+            // Structs are checked based on if they follow the power alignment
+            // rule (under repr(C)).
+            hir::ItemKind::Struct(..) => {
+                self.check_struct_for_power_alignment(cx, item);
+            }
             // See `check_field_def`..
-            hir::ItemKind::Union(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) => {}
+            hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {}
             // Doesn't define something that can contain a external type to be checked.
             hir::ItemKind::Impl(..)
             | hir::ItemKind::TraitAlias(..)
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 9fc527a6a3a..5b4a1f174cb 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -60,6 +60,7 @@ declare_lint_pass! {
         LARGE_ASSIGNMENTS,
         LATE_BOUND_LIFETIME_ARGUMENTS,
         LEGACY_DERIVE_HELPERS,
+        LINKER_MESSAGES,
         LONG_RUNNING_CONST_EVAL,
         LOSSY_PROVENANCE_CASTS,
         MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
@@ -143,7 +144,6 @@ declare_lint_pass! {
         UNUSED_VARIABLES,
         USELESS_DEPRECATED,
         WARNINGS,
-        WASM_C_ABI,
         // tidy-alphabetical-end
     ]
 }
@@ -4086,6 +4086,47 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `linker_messages` lint forwards warnings from the linker.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (needs CLI args, platform-specific)
+    /// #[warn(linker_messages)]
+    /// extern "C" {
+    ///   fn foo();
+    /// }
+    /// fn main () { unsafe { foo(); } }
+    /// ```
+    ///
+    /// On Linux, using `gcc -Wl,--warn-unresolved-symbols` as a linker, this will produce
+    ///
+    /// ```text
+    /// warning: linker stderr: rust-lld: undefined symbol: foo
+    ///          >>> referenced by rust_out.69edbd30df4ae57d-cgu.0
+    ///          >>>               rust_out.rust_out.69edbd30df4ae57d-cgu.0.rcgu.o:(rust_out::main::h3a90094b06757803)
+    ///   |
+    /// note: the lint level is defined here
+    ///  --> warn.rs:1:9
+    ///   |
+    /// 1 | #![warn(linker_messages)]
+    ///   |         ^^^^^^^^^^^^^^^
+    /// warning: 1 warning emitted
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// Linkers emit platform-specific and program-specific warnings that cannot be predicted in
+    /// advance by the Rust compiler. Such messages are ignored by default for now. While linker
+    /// warnings could be very useful they have been ignored for many years by essentially all
+    /// users, so we need to do a bit more work than just surfacing their text to produce a clear
+    /// and actionable warning of similar quality to our other diagnostics. See this tracking
+    /// issue for more details: <https://github.com/rust-lang/rust/issues/136096>.
+    pub LINKER_MESSAGES,
+    Allow,
+    "warnings emitted at runtime by the target-specific linker program"
+}
+
+declare_lint! {
     /// The `named_arguments_used_positionally` lint detects cases where named arguments are only
     /// used positionally in format strings. This usage is valid but potentially very confusing.
     ///
@@ -4648,44 +4689,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `wasm_c_abi` lint detects crate dependencies that are incompatible
-    /// with future versions of Rust that will emit spec-compliant C ABI.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,ignore (needs extern crate)
-    /// #![deny(wasm_c_abi)]
-    /// ```
-    ///
-    /// This will produce:
-    ///
-    /// ```text
-    /// error: the following packages contain code that will be rejected by a future version of Rust: wasm-bindgen v0.2.87
-    ///   |
-    /// note: the lint level is defined here
-    ///  --> src/lib.rs:1:9
-    ///   |
-    /// 1 | #![deny(wasm_c_abi)]
-    ///   |         ^^^^^^^^^^
-    /// ```
-    ///
-    /// ### Explanation
-    ///
-    /// Rust has historically emitted non-spec-compliant C ABI. This has caused
-    /// incompatibilities between other compilers and Wasm targets. In a future
-    /// version of Rust this will be fixed and therefore dependencies relying
-    /// on the non-spec-compliant C ABI will stop functioning.
-    pub WASM_C_ABI,
-    Deny,
-    "detects dependencies that are incompatible with the Wasm C ABI",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
-        reference: "issue #71871 <https://github.com/rust-lang/rust/issues/71871>",
-    };
-    crate_level_only
-}
-
-declare_lint! {
     /// The `uncovered_param_in_projection` lint detects a violation of one of Rust's orphan rules for
     /// foreign trait implementations that concerns the use of type parameters inside trait associated
     /// type paths ("projections") whose output may not be a local type that is mistakenly considered
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 7786d3eb59a..3f1e98556ef 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -161,7 +161,19 @@ impl<HCX: rustc_hir::HashStableContext> ToStableHashKey<HCX> for LintExpectation
 /// Setting for how to handle a lint.
 ///
 /// See: <https://doc.rust-lang.org/rustc/lints/levels.html>
-#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, HashStable_Generic)]
+#[derive(
+    Clone,
+    Copy,
+    PartialEq,
+    PartialOrd,
+    Eq,
+    Ord,
+    Debug,
+    Hash,
+    Encodable,
+    Decodable,
+    HashStable_Generic
+)]
 pub enum Level {
     /// The `allow` level will not issue any message.
     Allow,
@@ -783,7 +795,6 @@ pub enum BuiltinLintDiag {
         extern_crate: Symbol,
         local_crate: Symbol,
     },
-    WasmCAbi,
     IllFormedAttributeInput {
         suggestions: Vec<String>,
     },
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index dd72ea2497f..35186778671 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -2,6 +2,7 @@
 
 #include "llvm-c/Analysis.h"
 #include "llvm-c/Core.h"
+#include "llvm-c/DebugInfo.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
@@ -676,120 +677,73 @@ template <typename DIT> DIT *unwrapDIPtr(LLVMMetadataRef Ref) {
 #define DIArray DINodeArray
 #define unwrapDI unwrapDIPtr
 
-// These values **must** match debuginfo::DIFlags! They also *happen*
-// to match LLVM, but that isn't required as we do giant sets of
-// matching below. The value shouldn't be directly passed to LLVM.
-enum class LLVMRustDIFlags : uint32_t {
-  FlagZero = 0,
-  FlagPrivate = 1,
-  FlagProtected = 2,
-  FlagPublic = 3,
-  FlagFwdDecl = (1 << 2),
-  FlagAppleBlock = (1 << 3),
-  FlagBlockByrefStruct = (1 << 4),
-  FlagVirtual = (1 << 5),
-  FlagArtificial = (1 << 6),
-  FlagExplicit = (1 << 7),
-  FlagPrototyped = (1 << 8),
-  FlagObjcClassComplete = (1 << 9),
-  FlagObjectPointer = (1 << 10),
-  FlagVector = (1 << 11),
-  FlagStaticMember = (1 << 12),
-  FlagLValueReference = (1 << 13),
-  FlagRValueReference = (1 << 14),
-  FlagExternalTypeRef = (1 << 15),
-  FlagIntroducedVirtual = (1 << 18),
-  FlagBitField = (1 << 19),
-  FlagNoReturn = (1 << 20),
-  // Do not add values that are not supported by the minimum LLVM
-  // version we support! see llvm/include/llvm/IR/DebugInfoFlags.def
-};
-
-inline LLVMRustDIFlags operator&(LLVMRustDIFlags A, LLVMRustDIFlags B) {
-  return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(A) &
-                                      static_cast<uint32_t>(B));
-}
-
-inline LLVMRustDIFlags operator|(LLVMRustDIFlags A, LLVMRustDIFlags B) {
-  return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(A) |
-                                      static_cast<uint32_t>(B));
-}
-
-inline LLVMRustDIFlags &operator|=(LLVMRustDIFlags &A, LLVMRustDIFlags B) {
-  return A = A | B;
-}
-
-inline bool isSet(LLVMRustDIFlags F) { return F != LLVMRustDIFlags::FlagZero; }
-
-inline LLVMRustDIFlags visibility(LLVMRustDIFlags F) {
-  return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(F) & 0x3);
-}
-
-static DINode::DIFlags fromRust(LLVMRustDIFlags Flags) {
-  DINode::DIFlags Result = DINode::DIFlags::FlagZero;
-
-  switch (visibility(Flags)) {
-  case LLVMRustDIFlags::FlagPrivate:
-    Result |= DINode::DIFlags::FlagPrivate;
-    break;
-  case LLVMRustDIFlags::FlagProtected:
-    Result |= DINode::DIFlags::FlagProtected;
-    break;
-  case LLVMRustDIFlags::FlagPublic:
-    Result |= DINode::DIFlags::FlagPublic;
-    break;
-  default:
-    // The rest are handled below
-    break;
-  }
-
-  if (isSet(Flags & LLVMRustDIFlags::FlagFwdDecl)) {
-    Result |= DINode::DIFlags::FlagFwdDecl;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagAppleBlock)) {
-    Result |= DINode::DIFlags::FlagAppleBlock;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagVirtual)) {
-    Result |= DINode::DIFlags::FlagVirtual;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagArtificial)) {
-    Result |= DINode::DIFlags::FlagArtificial;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagExplicit)) {
-    Result |= DINode::DIFlags::FlagExplicit;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagPrototyped)) {
-    Result |= DINode::DIFlags::FlagPrototyped;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagObjcClassComplete)) {
-    Result |= DINode::DIFlags::FlagObjcClassComplete;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagObjectPointer)) {
-    Result |= DINode::DIFlags::FlagObjectPointer;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagVector)) {
-    Result |= DINode::DIFlags::FlagVector;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagStaticMember)) {
-    Result |= DINode::DIFlags::FlagStaticMember;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagLValueReference)) {
-    Result |= DINode::DIFlags::FlagLValueReference;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagRValueReference)) {
-    Result |= DINode::DIFlags::FlagRValueReference;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagIntroducedVirtual)) {
-    Result |= DINode::DIFlags::FlagIntroducedVirtual;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagBitField)) {
-    Result |= DINode::DIFlags::FlagBitField;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagNoReturn)) {
-    Result |= DINode::DIFlags::FlagNoReturn;
-  }
-
-  return Result;
+// FIXME(Zalathar): This is a temporary typedef to avoid churning dozens of
+// bindings that are going to be deleted and replaced with their LLVM-C
+// equivalents, as part of #134009. After that happens, the remaining bindings
+// can be adjusted to use `LLVMDIFlags` instead of relying on this typedef.
+typedef LLVMDIFlags LLVMRustDIFlags;
+
+// Statically assert that `LLVMDIFlags` (C) and `DIFlags` (C++) have the same
+// layout, at least for the flags we know about. This isn't guaranteed, but is
+// likely to remain true, and as long as it is true it makes conversions easy.
+#define ASSERT_DIFLAG_VALUE(FLAG, VALUE)                                       \
+  static_assert((LLVMDI##FLAG == (VALUE)) && (DINode::DIFlags::FLAG == (VALUE)))
+ASSERT_DIFLAG_VALUE(FlagZero, 0);
+ASSERT_DIFLAG_VALUE(FlagPrivate, 1);
+ASSERT_DIFLAG_VALUE(FlagProtected, 2);
+ASSERT_DIFLAG_VALUE(FlagPublic, 3);
+// Bit (1 << 1) is part of the private/protected/public values above.
+ASSERT_DIFLAG_VALUE(FlagFwdDecl, 1 << 2);
+ASSERT_DIFLAG_VALUE(FlagAppleBlock, 1 << 3);
+ASSERT_DIFLAG_VALUE(FlagReservedBit4, 1 << 4);
+ASSERT_DIFLAG_VALUE(FlagVirtual, 1 << 5);
+ASSERT_DIFLAG_VALUE(FlagArtificial, 1 << 6);
+ASSERT_DIFLAG_VALUE(FlagExplicit, 1 << 7);
+ASSERT_DIFLAG_VALUE(FlagPrototyped, 1 << 8);
+ASSERT_DIFLAG_VALUE(FlagObjcClassComplete, 1 << 9);
+ASSERT_DIFLAG_VALUE(FlagObjectPointer, 1 << 10);
+ASSERT_DIFLAG_VALUE(FlagVector, 1 << 11);
+ASSERT_DIFLAG_VALUE(FlagStaticMember, 1 << 12);
+ASSERT_DIFLAG_VALUE(FlagLValueReference, 1 << 13);
+ASSERT_DIFLAG_VALUE(FlagRValueReference, 1 << 14);
+// Bit (1 << 15) has been recycled, but the C API value hasn't been renamed.
+static_assert((LLVMDIFlagReserved == (1 << 15)) &&
+              (DINode::DIFlags::FlagExportSymbols == (1 << 15)));
+ASSERT_DIFLAG_VALUE(FlagSingleInheritance, 1 << 16);
+ASSERT_DIFLAG_VALUE(FlagMultipleInheritance, 2 << 16);
+ASSERT_DIFLAG_VALUE(FlagVirtualInheritance, 3 << 16);
+// Bit (1 << 17) is part of the inheritance values above.
+ASSERT_DIFLAG_VALUE(FlagIntroducedVirtual, 1 << 18);
+ASSERT_DIFLAG_VALUE(FlagBitField, 1 << 19);
+ASSERT_DIFLAG_VALUE(FlagNoReturn, 1 << 20);
+// Bit (1 << 21) is unused, but was `LLVMDIFlagMainSubprogram`.
+ASSERT_DIFLAG_VALUE(FlagTypePassByValue, 1 << 22);
+ASSERT_DIFLAG_VALUE(FlagTypePassByReference, 1 << 23);
+ASSERT_DIFLAG_VALUE(FlagEnumClass, 1 << 24);
+ASSERT_DIFLAG_VALUE(FlagThunk, 1 << 25);
+ASSERT_DIFLAG_VALUE(FlagNonTrivial, 1 << 26);
+ASSERT_DIFLAG_VALUE(FlagBigEndian, 1 << 27);
+ASSERT_DIFLAG_VALUE(FlagLittleEndian, 1 << 28);
+ASSERT_DIFLAG_VALUE(FlagIndirectVirtualBase, (1 << 2) | (1 << 5));
+#undef ASSERT_DIFLAG_VALUE
+
+// There are two potential ways to convert `LLVMDIFlags` to `DIFlags`:
+// - Check and copy every individual bit/subvalue from input to output.
+// - Statically assert that both have the same layout, and cast.
+// As long as the static assertions succeed, a cast is easier and faster.
+// In the (hopefully) unlikely event that the assertions do fail someday, and
+// LLVM doesn't expose its own conversion function, we'll have to switch over
+// to copying each bit/subvalue.
+static DINode::DIFlags fromRust(LLVMDIFlags Flags) {
+  // Check that all set bits are covered by the static assertions above.
+  const unsigned UNKNOWN_BITS = (1 << 31) | (1 << 30) | (1 << 29) | (1 << 21);
+  if (Flags & UNKNOWN_BITS) {
+    report_fatal_error("bad LLVMDIFlags");
+  }
+
+  // As long as the static assertions are satisfied and no unknown bits are
+  // present, we can convert from `LLVMDIFlags` to `DIFlags` with a cast.
+  return static_cast<DINode::DIFlags>(Flags);
 }
 
 // These values **must** match debuginfo::DISPFlags! They also *happen*
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index 6d7d88fa8d7..d2b5ae53185 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -290,6 +290,9 @@ metadata_unsupported_abi =
 metadata_unsupported_abi_i686 =
     ABI not supported by `#[link(kind = "raw-dylib")]` on i686
 
+metadata_wasm_c_abi =
+    older versions of the `wasm-bindgen` crate are incompatible with current versions of Rust; please update to `wasm-bindgen` v0.2.88
+
 metadata_wasm_import_form =
     wasm import module must be of the form `wasm_import_module = "string"`
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 6512176cc4a..a6cd0ecafd0 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -417,7 +417,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // Any descendants of `std` should be private. These crates are usually not marked
         // private in metadata, so we ignore that field.
         if extern_private.is_none()
-            && dep_root.map_or(false, |d| STDLIB_STABLE_CRATES.contains(&d.name))
+            && let Some(dep) = dep_root
+            && STDLIB_STABLE_CRATES.contains(&dep.name)
         {
             return true;
         }
@@ -1075,12 +1076,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             // Make a point span rather than covering the whole file
             let span = krate.spans.inner_span.shrink_to_lo();
 
-            self.sess.psess.buffer_lint(
-                lint::builtin::WASM_C_ABI,
-                span,
-                ast::CRATE_NODE_ID,
-                BuiltinLintDiag::WasmCAbi,
-            );
+            self.sess.dcx().emit_err(errors::WasmCAbi { span });
         }
     }
 
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index b6c5619ec18..cefc6498f68 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -732,3 +732,10 @@ pub struct ImportNameTypeRaw {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(metadata_wasm_c_abi)]
+pub(crate) struct WasmCAbi {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 5dd85978f00..8dc529b4d7a 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -100,6 +100,8 @@ middle_strict_coherence_needs_negative_coherence =
     to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
     .label = due to this attribute
 
+middle_too_generic = `{$ty}` does not have a fixed size
+
 middle_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
 
 middle_unknown_layout =
@@ -107,4 +109,5 @@ middle_unknown_layout =
 
 middle_values_too_big =
     values of the type `{$ty}` are too big for the target architecture
+
 middle_written_to_path = the full type name has been written to '{$path}'
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index 6300d856393..b0187a1848c 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -129,6 +129,9 @@ pub enum LayoutError<'tcx> {
     #[diag(middle_unknown_layout)]
     Unknown { ty: Ty<'tcx> },
 
+    #[diag(middle_too_generic)]
+    TooGeneric { ty: Ty<'tcx> },
+
     #[diag(middle_values_too_big)]
     Overflow { ty: Ty<'tcx> },
 
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 5d78bed5cf8..926760b84aa 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -12,7 +12,7 @@ use rustc_hir::*;
 use rustc_hir_pretty as pprust_hir;
 use rustc_middle::hir::nested_filter;
 use rustc_span::def_id::StableCrateId;
-use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
+use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym, with_metavar_spans};
 
 use crate::hir::ModuleItems;
 use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
@@ -1117,6 +1117,9 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
         // the fly in the resolver, storing only their accumulated hash in `ResolverGlobalCtxt`,
         // and combining it with other hashes here.
         resolutions.visibilities_for_hashing.hash_stable(&mut hcx, &mut stable_hasher);
+        with_metavar_spans(|mspans| {
+            mspans.freeze_and_get_read_spans().hash_stable(&mut hcx, &mut stable_hasher);
+        });
         stable_hasher.finish()
     });
 
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 04a06ba7464..bbe23d8abe8 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -40,6 +40,7 @@
 #![feature(const_type_name)]
 #![feature(core_intrinsics)]
 #![feature(coroutines)]
+#![feature(debug_closure_helpers)]
 #![feature(decl_macro)]
 #![feature(discriminant_kind)]
 #![feature(extern_types)]
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 620d9f1c357..cae980cde61 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_errors::{Diag, MultiSpan};
 use rustc_hir::{HirId, ItemLocalId};
-use rustc_macros::HashStable;
+use rustc_macros::{Decodable, Encodable, HashStable};
 use rustc_session::Session;
 use rustc_session::lint::builtin::{self, FORBIDDEN_LINT_GROUPS};
 use rustc_session::lint::{FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId};
@@ -15,7 +15,7 @@ use tracing::instrument;
 use crate::ty::TyCtxt;
 
 /// How a lint level was set.
-#[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, HashStable, Debug)]
 pub enum LintLevelSource {
     /// Lint is at the default level as declared in rustc.
     Default,
@@ -173,7 +173,7 @@ impl TyCtxt<'_> {
 /// This struct represents a lint expectation and holds all required information
 /// to emit the `unfulfilled_lint_expectations` lint if it is unfulfilled after
 /// the `LateLintPass` has completed.
-#[derive(Clone, Debug, HashStable)]
+#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
 pub struct LintExpectation {
     /// The reason for this expectation that can optionally be added as part of
     /// the attribute. It will be displayed as part of the lint message.
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index e05f42af6fd..cc980f6e62a 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -147,7 +147,7 @@ impl CodegenFnAttrs {
         CodegenFnAttrs {
             flags: CodegenFnAttrFlags::empty(),
             inline: InlineAttr::None,
-            optimize: OptimizeAttr::None,
+            optimize: OptimizeAttr::Default,
             export_name: None,
             link_name: None,
             link_ordinal: None,
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 60e1ff1d049..66d97fda433 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -460,17 +460,6 @@ impl<'tcx> Const<'tcx> {
         Self::Val(val, ty)
     }
 
-    pub fn from_ty_const(c: ty::Const<'tcx>, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
-        match c.kind() {
-            ty::ConstKind::Value(ty, valtree) => {
-                // Make sure that if `c` is normalized, then the return value is normalized.
-                let const_val = tcx.valtree_to_const_val((ty, valtree));
-                Self::Val(const_val, ty)
-            }
-            _ => Self::Ty(ty, c),
-        }
-    }
-
     /// Return true if any evaluation of this constant always returns the same value,
     /// taking into account even pointer identity tests.
     pub fn is_deterministic(&self) -> bool {
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 65f51ae9d39..46534697e1d 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -4,7 +4,7 @@ use std::fmt::{self, Debug, Formatter};
 
 use rustc_index::IndexVec;
 use rustc_index::bit_set::DenseBitSet;
-use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
+use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_span::Span;
 
 rustc_index::newtype_index! {
@@ -72,7 +72,7 @@ impl ConditionId {
 /// Enum that can hold a constant zero value, the ID of an physical coverage
 /// counter, or the ID of a coverage-counter expression.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum CovTerm {
     Zero,
     Counter(CounterId),
@@ -89,7 +89,7 @@ impl Debug for CovTerm {
     }
 }
 
-#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum CoverageKind {
     /// Marks a span that might otherwise not be represented in MIR, so that
     /// coverage instrumentation can associate it with its enclosing block/BCB.
@@ -151,7 +151,7 @@ impl Debug for CoverageKind {
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
-#[derive(TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
+#[derive(TyEncodable, TyDecodable)]
 pub enum Op {
     Subtract,
     Add,
@@ -168,7 +168,7 @@ impl Op {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
-#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct Expression {
     pub lhs: CovTerm,
     pub op: Op,
@@ -176,7 +176,7 @@ pub struct Expression {
 }
 
 #[derive(Clone, Debug)]
-#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum MappingKind {
     /// Associates a normal region of code with a counter/expression/zero.
     Code(CovTerm),
@@ -208,7 +208,7 @@ impl MappingKind {
 }
 
 #[derive(Clone, Debug)]
-#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct Mapping {
     pub kind: MappingKind,
     pub span: Span,
@@ -218,7 +218,7 @@ pub struct Mapping {
 /// to be used in conjunction with the individual coverage statements injected
 /// into the function's basic blocks.
 #[derive(Clone, Debug)]
-#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct FunctionCoverageInfo {
     pub function_source_hash: u64,
     pub body_span: Span,
@@ -238,7 +238,7 @@ pub struct FunctionCoverageInfo {
 /// ("Hi" indicates that this is "high-level" information collected at the
 /// THIR/MIR boundary, before the MIR-based coverage instrumentation pass.)
 #[derive(Clone, Debug)]
-#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct CoverageInfoHi {
     /// 1 more than the highest-numbered [`CoverageKind::BlockMarker`] that was
     /// injected into the MIR body. This makes it possible to allocate per-ID
@@ -252,7 +252,7 @@ pub struct CoverageInfoHi {
 }
 
 #[derive(Clone, Debug)]
-#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct BranchSpan {
     pub span: Span,
     pub true_marker: BlockMarkerId,
@@ -260,7 +260,7 @@ pub struct BranchSpan {
 }
 
 #[derive(Copy, Clone, Debug)]
-#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct ConditionInfo {
     pub condition_id: ConditionId,
     pub true_next_id: Option<ConditionId>,
@@ -268,7 +268,7 @@ pub struct ConditionInfo {
 }
 
 #[derive(Clone, Debug)]
-#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct MCDCBranchSpan {
     pub span: Span,
     pub condition_info: ConditionInfo,
@@ -277,14 +277,14 @@ pub struct MCDCBranchSpan {
 }
 
 #[derive(Copy, Clone, Debug)]
-#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct DecisionInfo {
     pub bitmap_idx: u32,
     pub num_conditions: u16,
 }
 
 #[derive(Clone, Debug)]
-#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct MCDCDecisionSpan {
     pub span: Span,
     pub end_markers: Vec<BlockMarkerId>,
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index d6f8fed755f..1b07846e0cf 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -222,7 +222,7 @@ impl AllocError {
 }
 
 /// The information that makes up a memory access: offset and size.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, PartialEq)]
 pub struct AllocRange {
     pub start: Size,
     pub size: Size,
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
index 3a83b184d83..78196b05361 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
@@ -97,7 +97,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
         debug_assert!(prov.len() <= 1);
         if let Some(entry) = prov.first() {
             // If it overlaps with this byte, it is on this byte.
-            debug_assert!(self.bytes.as_ref().map_or(true, |b| b.get(&offset).is_none()));
+            debug_assert!(self.bytes.as_ref().is_none_or(|b| !b.contains_key(&offset)));
             Some(entry.1)
         } else {
             // Look up per-byte provenance.
@@ -301,7 +301,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
                 // For really small copies, make sure we don't start before `src` does.
                 let entry_start = cmp::max(entry.0, src.start);
                 for offset in entry_start..src.end() {
-                    if bytes.last().map_or(true, |bytes_entry| bytes_entry.0 < offset) {
+                    if bytes.last().is_none_or(|bytes_entry| bytes_entry.0 < offset) {
                         // The last entry, if it exists, has a lower offset than us.
                         bytes.push((offset, entry.1));
                     } else {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index bbb8bdce4a0..0f3fca434ee 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -358,6 +358,8 @@ pub struct Body<'tcx> {
     ///
     /// Only present if coverage is enabled and this function is eligible.
     /// Boxed to limit space overhead in non-coverage builds.
+    #[type_foldable(identity)]
+    #[type_visitable(ignore)]
     pub coverage_info_hi: Option<Box<coverage::CoverageInfoHi>>,
 
     /// Per-function coverage information added by the `InstrumentCoverage`
@@ -366,6 +368,8 @@ pub struct Body<'tcx> {
     ///
     /// If `-Cinstrument-coverage` is not active, or if an individual function
     /// is not eligible for coverage, then this should always be `None`.
+    #[type_foldable(identity)]
+    #[type_visitable(ignore)]
     pub function_coverage_info: Option<Box<coverage::FunctionCoverageInfo>>,
 }
 
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 111c3b6956a..3eccf56d8c4 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher, ToStableHashKey};
 use rustc_data_structures::unord::UnordMap;
 use rustc_hir::ItemId;
-use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LOCAL_CRATE};
 use rustc_index::Idx;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_query_system::ich::StableHashingContext;
@@ -247,6 +247,12 @@ impl ToStableHashKey<StableHashingContext<'_>> for MonoItem<'_> {
     }
 }
 
+#[derive(Debug, HashStable, Copy, Clone)]
+pub struct MonoItemPartitions<'tcx> {
+    pub codegen_units: &'tcx [CodegenUnit<'tcx>],
+    pub all_mono_items: &'tcx DefIdSet,
+}
+
 #[derive(Debug, HashStable)]
 pub struct CodegenUnit<'tcx> {
     /// A name for this CGU. Incremental compilation requires that
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index ea35323ccc7..3b4fba97e60 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1,8 +1,7 @@
 use std::collections::BTreeSet;
 use std::fmt::{Display, Write as _};
-use std::fs;
-use std::io::{self, Write as _};
 use std::path::{Path, PathBuf};
+use std::{fs, io};
 
 use rustc_abi::Size;
 use rustc_ast::InlineAsmTemplatePiece;
@@ -149,37 +148,59 @@ pub fn dump_enabled(tcx: TyCtxt<'_>, pass_name: &str, def_id: DefId) -> bool {
 // `def_path_str()` would otherwise trigger `type_of`, and this can
 // run while we are already attempting to evaluate `type_of`.
 
+/// Most use-cases of dumping MIR should use the [dump_mir] entrypoint instead, which will also
+/// check if dumping MIR is enabled, and if this body matches the filters passed on the CLI.
+///
+/// That being said, if the above requirements have been validated already, this function is where
+/// most of the MIR dumping occurs, if one needs to export it to a file they have created with
+/// [create_dump_file], rather than to a new file created as part of [dump_mir], or to stdout/stderr
+/// for debugging purposes.
+pub fn dump_mir_to_writer<'tcx, F>(
+    tcx: TyCtxt<'tcx>,
+    pass_name: &str,
+    disambiguator: &dyn Display,
+    body: &Body<'tcx>,
+    w: &mut dyn io::Write,
+    mut extra_data: F,
+    options: PrettyPrintMirOptions,
+) -> io::Result<()>
+where
+    F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>,
+{
+    // see notes on #41697 above
+    let def_path =
+        ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id()));
+    // ignore-tidy-odd-backticks the literal below is fine
+    write!(w, "// MIR for `{def_path}")?;
+    match body.source.promoted {
+        None => write!(w, "`")?,
+        Some(promoted) => write!(w, "::{promoted:?}`")?,
+    }
+    writeln!(w, " {disambiguator} {pass_name}")?;
+    if let Some(ref layout) = body.coroutine_layout_raw() {
+        writeln!(w, "/* coroutine_layout = {layout:#?} */")?;
+    }
+    writeln!(w)?;
+    extra_data(PassWhere::BeforeCFG, w)?;
+    write_user_type_annotations(tcx, body, w)?;
+    write_mir_fn(tcx, body, &mut extra_data, w, options)?;
+    extra_data(PassWhere::AfterCFG, w)
+}
+
 fn dump_matched_mir_node<'tcx, F>(
     tcx: TyCtxt<'tcx>,
     pass_num: bool,
     pass_name: &str,
     disambiguator: &dyn Display,
     body: &Body<'tcx>,
-    mut extra_data: F,
+    extra_data: F,
     options: PrettyPrintMirOptions,
 ) where
     F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>,
 {
     let _: io::Result<()> = try {
         let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body)?;
-        // see notes on #41697 above
-        let def_path =
-            ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id()));
-        // ignore-tidy-odd-backticks the literal below is fine
-        write!(file, "// MIR for `{def_path}")?;
-        match body.source.promoted {
-            None => write!(file, "`")?,
-            Some(promoted) => write!(file, "::{promoted:?}`")?,
-        }
-        writeln!(file, " {disambiguator} {pass_name}")?;
-        if let Some(ref layout) = body.coroutine_layout_raw() {
-            writeln!(file, "/* coroutine_layout = {layout:#?} */")?;
-        }
-        writeln!(file)?;
-        extra_data(PassWhere::BeforeCFG, &mut file)?;
-        write_user_type_annotations(tcx, body, &mut file)?;
-        write_mir_fn(tcx, body, &mut extra_data, &mut file, options)?;
-        extra_data(PassWhere::AfterCFG, &mut file)?;
+        dump_mir_to_writer(tcx, pass_name, disambiguator, body, &mut file, extra_data, options)?;
     };
 
     if tcx.sess.opts.unstable_opts.dump_mir_graphviz {
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index db5da941f1e..50494355e3e 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -1,6 +1,5 @@
 //! Values computed by queries that use MIR.
 
-use std::cell::Cell;
 use std::fmt::{self, Debug};
 
 use rustc_abi::{FieldIdx, VariantIdx};
@@ -62,55 +61,26 @@ pub struct CoroutineLayout<'tcx> {
 
 impl Debug for CoroutineLayout<'_> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        /// Prints an iterator of (key, value) tuples as a map.
-        struct MapPrinter<'a, K, V>(Cell<Option<Box<dyn Iterator<Item = (K, V)> + 'a>>>);
-        impl<'a, K, V> MapPrinter<'a, K, V> {
-            fn new(iter: impl Iterator<Item = (K, V)> + 'a) -> Self {
-                Self(Cell::new(Some(Box::new(iter))))
-            }
-        }
-        impl<'a, K: Debug, V: Debug> Debug for MapPrinter<'a, K, V> {
-            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-                fmt.debug_map().entries(self.0.take().unwrap()).finish()
-            }
-        }
-
-        /// Prints the coroutine variant name.
-        struct GenVariantPrinter(VariantIdx);
-        impl From<VariantIdx> for GenVariantPrinter {
-            fn from(idx: VariantIdx) -> Self {
-                GenVariantPrinter(idx)
-            }
-        }
-        impl Debug for GenVariantPrinter {
-            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-                let variant_name = ty::CoroutineArgs::variant_name(self.0);
-                if fmt.alternate() {
-                    write!(fmt, "{:9}({:?})", variant_name, self.0)
-                } else {
-                    write!(fmt, "{variant_name}")
-                }
-            }
-        }
-
-        /// Forces its contents to print in regular mode instead of alternate mode.
-        struct OneLinePrinter<T>(T);
-        impl<T: Debug> Debug for OneLinePrinter<T> {
-            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-                write!(fmt, "{:?}", self.0)
-            }
-        }
-
         fmt.debug_struct("CoroutineLayout")
-            .field("field_tys", &MapPrinter::new(self.field_tys.iter_enumerated()))
-            .field(
-                "variant_fields",
-                &MapPrinter::new(
-                    self.variant_fields
-                        .iter_enumerated()
-                        .map(|(k, v)| (GenVariantPrinter(k), OneLinePrinter(v))),
-                ),
-            )
+            .field_with("field_tys", |fmt| {
+                fmt.debug_map().entries(self.field_tys.iter_enumerated()).finish()
+            })
+            .field_with("variant_fields", |fmt| {
+                let mut map = fmt.debug_map();
+                for (idx, fields) in self.variant_fields.iter_enumerated() {
+                    map.key_with(|fmt| {
+                        let variant_name = ty::CoroutineArgs::variant_name(idx);
+                        if fmt.alternate() {
+                            write!(fmt, "{variant_name:9}({idx:?})")
+                        } else {
+                            write!(fmt, "{variant_name}")
+                        }
+                    });
+                    // Force variant fields to print in regular mode instead of alternate mode.
+                    map.value_with(|fmt| write!(fmt, "{fields:?}"));
+                }
+                map.finish()
+            })
             .field("storage_conflicts", &self.storage_conflicts)
             .finish()
     }
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 0c17a2e0fe5..29ae2e1bd6b 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -417,7 +417,14 @@ pub enum StatementKind<'tcx> {
     ///
     /// Interpreters and codegen backends that don't support coverage instrumentation
     /// can usually treat this as a no-op.
-    Coverage(CoverageKind),
+    Coverage(
+        // Coverage statements are unlikely to ever contain type information in
+        // the foreseeable future, so excluding them from TypeFoldable/TypeVisitable
+        // avoids some unhelpful derive boilerplate.
+        #[type_foldable(identity)]
+        #[type_visitable(ignore)]
+        CoverageKind,
+    ),
 
     /// Denotes a call to an intrinsic that does not require an unwind path and always returns.
     /// This avoids adding a new block and a terminator for simple intrinsics.
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 473b817aed0..c04a8251fbc 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -581,9 +581,11 @@ impl<'tcx> TerminatorKind<'tcx> {
 pub enum TerminatorEdges<'mir, 'tcx> {
     /// For terminators that have no successor, like `return`.
     None,
-    /// For terminators that a single successor, like `goto`, and `assert` without cleanup block.
+    /// For terminators that have a single successor, like `goto`, and `assert` without a cleanup
+    /// block.
     Single(BasicBlock),
-    /// For terminators that two successors, `assert` with cleanup block and `falseEdge`.
+    /// For terminators that have two successors, like `assert` with a cleanup block, and
+    /// `falseEdge`.
     Double(BasicBlock, BasicBlock),
     /// Special action for `Yield`, `Call` and `InlineAsm` terminators.
     AssignOnReturn {
diff --git a/compiler/rustc_middle/src/query/arena_cached.rs b/compiler/rustc_middle/src/query/arena_cached.rs
new file mode 100644
index 00000000000..ec6e466ff68
--- /dev/null
+++ b/compiler/rustc_middle/src/query/arena_cached.rs
@@ -0,0 +1,47 @@
+/// Helper trait that allows `arena_cache` queries to return `Option<&T>`
+/// instead of `&Option<T>`, and avoid allocating `None` in the arena.
+///
+/// An arena-cached query must be declared to return a type that implements
+/// this trait, i.e. either `&'tcx T` or `Option<&'tcx T>`. This trait then
+/// determines the types returned by the provider and stored in the arena,
+/// and provides a function to bridge between the three types.
+pub trait ArenaCached<'tcx>: Sized {
+    /// Type that is returned by the query provider.
+    type Provided;
+    /// Type that is stored in the arena.
+    type Allocated: 'tcx;
+
+    /// Takes a provided value, and allocates it in the arena (if appropriate)
+    /// with the help of the given `arena_alloc` closure.
+    fn alloc_in_arena(
+        arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
+        value: Self::Provided,
+    ) -> Self;
+}
+
+impl<'tcx, T> ArenaCached<'tcx> for &'tcx T {
+    type Provided = T;
+    type Allocated = T;
+
+    fn alloc_in_arena(
+        arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
+        value: Self::Provided,
+    ) -> Self {
+        // Just allocate in the arena normally.
+        arena_alloc(value)
+    }
+}
+
+impl<'tcx, T> ArenaCached<'tcx> for Option<&'tcx T> {
+    type Provided = Option<T>;
+    /// The provide value is `Option<T>`, but we only store `T` in the arena.
+    type Allocated = T;
+
+    fn alloc_in_arena(
+        arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
+        value: Self::Provided,
+    ) -> Self {
+        // Don't store None in the arena, and wrap the allocated reference in Some.
+        value.map(arena_alloc)
+    }
+}
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 1676afb4b6e..14f871cbbdc 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -349,6 +349,7 @@ tcx_lifetime! {
     rustc_middle::mir::interpret::GlobalId,
     rustc_middle::mir::interpret::LitToConstInput,
     rustc_middle::mir::interpret::EvalStaticInitializerRawResult,
+    rustc_middle::mir::mono::MonoItemPartitions,
     rustc_middle::traits::query::MethodAutoderefStepsResult,
     rustc_middle::traits::query::type_op::AscribeUserType,
     rustc_middle::traits::query::type_op::Eq,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 65e93c3a1cc..e27a9823639 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -7,7 +7,6 @@
 #![allow(unused_parens)]
 
 use std::mem;
-use std::ops::Deref;
 use std::path::PathBuf;
 use std::sync::Arc;
 
@@ -24,7 +23,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::{DefKind, DocLinkResMap};
 use rustc_hir::def_id::{
-    CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId,
+    CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId,
 };
 use rustc_hir::lang_items::{LangItem, LanguageItems};
 use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate};
@@ -59,7 +58,7 @@ use crate::mir::interpret::{
     EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult,
     EvalToValTreeResult, GlobalId, LitToConstInput,
 };
-use crate::mir::mono::{CodegenUnit, CollectionMode, MonoItem};
+use crate::mir::mono::{CodegenUnit, CollectionMode, MonoItem, MonoItemPartitions};
 use crate::query::erase::{Erase, erase, restore};
 use crate::query::plumbing::{
     CyclePlaceholder, DynamicQuery, query_ensure, query_ensure_error_guaranteed, query_get_at,
@@ -85,6 +84,7 @@ use crate::ty::{
 };
 use crate::{dep_graph, mir, thir};
 
+mod arena_cached;
 pub mod erase;
 mod keys;
 pub use keys::{AsLocalKey, Key, LocalCrate};
@@ -586,7 +586,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query mir_coroutine_witnesses(key: DefId) -> &'tcx Option<mir::CoroutineLayout<'tcx>> {
+    query mir_coroutine_witnesses(key: DefId) -> Option<&'tcx mir::CoroutineLayout<'tcx>> {
         arena_cache
         desc { |tcx| "coroutine witness types for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
@@ -618,7 +618,9 @@ rustc_queries! {
     /// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
     /// (for compiler option `-Cinstrument-coverage`), after MIR optimizations
     /// have had a chance to potentially remove some of them.
-    query coverage_ids_info(key: ty::InstanceKind<'tcx>) -> &'tcx mir::coverage::CoverageIdsInfo {
+    ///
+    /// Returns `None` for functions that were not instrumented.
+    query coverage_ids_info(key: ty::InstanceKind<'tcx>) -> Option<&'tcx mir::coverage::CoverageIdsInfo> {
         desc { |tcx| "retrieving coverage IDs info from MIR for `{}`", tcx.def_path_str(key.def_id()) }
         arena_cache
     }
@@ -2164,7 +2166,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query collect_and_partition_mono_items(_: ()) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) {
+    query collect_and_partition_mono_items(_: ()) -> MonoItemPartitions<'tcx> {
         eval_always
         desc { "collect_and_partition_mono_items" }
     }
@@ -2415,7 +2417,7 @@ rustc_queries! {
     /// because the `ty::Ty`-based wfcheck is always run.
     query diagnostic_hir_wf_check(
         key: (ty::Predicate<'tcx>, WellFormedLoc)
-    ) -> &'tcx Option<ObligationCause<'tcx>> {
+    ) -> Option<&'tcx ObligationCause<'tcx>> {
         arena_cache
         eval_always
         no_hash
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 2cb6f6d8c6e..1c157f33a81 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -289,10 +289,10 @@ macro_rules! define_callbacks {
 
                 /// This type alias specifies the type returned from query providers and the type
                 /// used for decoding. For regular queries this is the declared returned type `V`,
-                /// but `arena_cache` will use `<V as Deref>::Target` instead.
+                /// but `arena_cache` will use `<V as ArenaCached>::Provided` instead.
                 pub type ProvidedValue<'tcx> = query_if_arena!(
                     [$($modifiers)*]
-                    (<$V as Deref>::Target)
+                    (<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Provided)
                     ($V)
                 );
 
@@ -307,10 +307,18 @@ macro_rules! define_callbacks {
                 ) -> Erase<Value<'tcx>> {
                     erase(query_if_arena!([$($modifiers)*]
                         {
-                            if mem::needs_drop::<ProvidedValue<'tcx>>() {
-                                &*_tcx.query_system.arenas.$name.alloc(value)
+                            use $crate::query::arena_cached::ArenaCached;
+
+                            if mem::needs_drop::<<$V as ArenaCached<'tcx>>::Allocated>() {
+                                <$V as ArenaCached>::alloc_in_arena(
+                                    |v| _tcx.query_system.arenas.$name.alloc(v),
+                                    value,
+                                )
                             } else {
-                                &*_tcx.arena.dropless.alloc(value)
+                                <$V as ArenaCached>::alloc_in_arena(
+                                    |v| _tcx.arena.dropless.alloc(v),
+                                    value,
+                                )
                             }
                         }
                         (value)
@@ -354,7 +362,7 @@ macro_rules! define_callbacks {
 
         pub struct QueryArenas<'tcx> {
             $($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*]
-                (TypedArena<<$V as Deref>::Target>)
+                (TypedArena<<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated>)
                 ()
             ),)*
         }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index db2bb8a7248..55d78e083e0 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -345,9 +345,6 @@ pub enum ObligationCauseCode<'tcx> {
     /// `main` has wrong type
     MainFunctionType,
 
-    /// `start` has wrong type
-    StartFunctionType,
-
     /// language function has wrong type
     LangFunctionType(Symbol),
 
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 33d39b137b6..c4d5367e2f0 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -433,7 +433,7 @@ pub fn analyze_coroutine_closure_captures<'a, 'tcx: 'a, T>(
                 // A parent matches a child if they share the same prefix of projections.
                 // The child may have more, if it is capturing sub-fields out of
                 // something that is captured by-move in the parent closure.
-                while child_captures.peek().map_or(false, |(_, child_capture)| {
+                while child_captures.peek().is_some_and(|(_, child_capture)| {
                     child_prefix_matches_parent_projections(parent_capture, child_capture)
                 }) {
                     let (child_field_idx, child_capture) = child_captures.next().unwrap();
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 7035e641f39..1f0710e2415 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -33,7 +33,7 @@ use rustc_errors::{
 use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::definitions::Definitions;
-use rustc_hir::intravisit::Visitor;
+use rustc_hir::intravisit::VisitorExt;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate};
 use rustc_index::IndexVec;
@@ -52,7 +52,9 @@ use rustc_type_ir::TyKind::*;
 use rustc_type_ir::fold::TypeFoldable;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 pub use rustc_type_ir::lift::Lift;
-use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph};
+use rustc_type_ir::{
+    CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, elaborate, search_graph,
+};
 use tracing::{debug, instrument};
 
 use crate::arena::Arena;
@@ -1347,6 +1349,33 @@ pub struct GlobalCtxt<'tcx> {
 
     /// Stores memory for globals (statics/consts).
     pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
+
+    current_gcx: CurrentGcx,
+}
+
+impl<'tcx> GlobalCtxt<'tcx> {
+    /// Installs `self` in a `TyCtxt` and `ImplicitCtxt` for the duration of
+    /// `f`.
+    pub fn enter<F, R>(&'tcx self, f: F) -> R
+    where
+        F: FnOnce(TyCtxt<'tcx>) -> R,
+    {
+        let icx = tls::ImplicitCtxt::new(self);
+
+        // Reset `current_gcx` to `None` when we exit.
+        let _on_drop = defer(move || {
+            *self.current_gcx.value.write() = None;
+        });
+
+        // Set this `GlobalCtxt` as the current one.
+        {
+            let mut guard = self.current_gcx.value.write();
+            assert!(guard.is_none(), "no `GlobalCtxt` is currently set");
+            *guard = Some(self as *const _ as *const ());
+        }
+
+        tls::enter_context(&icx, || f(icx.tcx))
+    }
 }
 
 /// This is used to get a reference to a `GlobalCtxt` if one is available.
@@ -1537,23 +1566,11 @@ impl<'tcx> TyCtxt<'tcx> {
             canonical_param_env_cache: Default::default(),
             data_layout,
             alloc_map: Lock::new(interpret::AllocMap::new()),
+            current_gcx,
         });
 
-        let icx = tls::ImplicitCtxt::new(&gcx);
-
-        // Reset `current_gcx` to `None` when we exit.
-        let _on_drop = defer(|| {
-            *current_gcx.value.write() = None;
-        });
-
-        // Set this `GlobalCtxt` as the current one.
-        {
-            let mut guard = current_gcx.value.write();
-            assert!(guard.is_none(), "no `GlobalCtxt` is currently set");
-            *guard = Some(&gcx as *const _ as *const ());
-        }
-
-        tls::enter_context(&icx, || f(icx.tcx))
+        // This is a separate function to work around a crash with parallel rustc (#135870)
+        gcx.enter(f)
     }
 
     /// Obtain all lang items of this crate and all dependencies (recursively)
@@ -2026,7 +2043,7 @@ impl<'tcx> TyCtxt<'tcx> {
         };
 
         let mut v = TraitObjectVisitor(vec![], self.hir());
-        v.visit_ty(hir_output);
+        v.visit_ty_unambig(hir_output);
         v.0
     }
 
@@ -2048,7 +2065,7 @@ impl<'tcx> TyCtxt<'tcx> {
             && let Some(alias_ty) = self.hir_node_by_def_id(local_id).alias_ty() // it is type alias
             && let Some(alias_generics) = self.hir_node_by_def_id(local_id).generics()
         {
-            v.visit_ty(alias_ty);
+            v.visit_ty_unambig(alias_ty);
             if !v.0.is_empty() {
                 return Some((
                     v.0,
@@ -2323,51 +2340,41 @@ macro_rules! sty_debug_print {
 }
 
 impl<'tcx> TyCtxt<'tcx> {
-    pub fn debug_stats(self) -> impl std::fmt::Debug + 'tcx {
-        struct DebugStats<'tcx>(TyCtxt<'tcx>);
-
-        impl<'tcx> std::fmt::Debug for DebugStats<'tcx> {
-            fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-                sty_debug_print!(
-                    fmt,
-                    self.0,
-                    Adt,
-                    Array,
-                    Slice,
-                    RawPtr,
-                    Ref,
-                    FnDef,
-                    FnPtr,
-                    UnsafeBinder,
-                    Placeholder,
-                    Coroutine,
-                    CoroutineWitness,
-                    Dynamic,
-                    Closure,
-                    CoroutineClosure,
-                    Tuple,
-                    Bound,
-                    Param,
-                    Infer,
-                    Alias,
-                    Pat,
-                    Foreign
-                )?;
-
-                writeln!(fmt, "GenericArgs interner: #{}", self.0.interners.args.len())?;
-                writeln!(fmt, "Region interner: #{}", self.0.interners.region.len())?;
-                writeln!(
-                    fmt,
-                    "Const Allocation interner: #{}",
-                    self.0.interners.const_allocation.len()
-                )?;
-                writeln!(fmt, "Layout interner: #{}", self.0.interners.layout.len())?;
-
-                Ok(())
-            }
-        }
-
-        DebugStats(self)
+    pub fn debug_stats(self) -> impl fmt::Debug + 'tcx {
+        fmt::from_fn(move |fmt| {
+            sty_debug_print!(
+                fmt,
+                self,
+                Adt,
+                Array,
+                Slice,
+                RawPtr,
+                Ref,
+                FnDef,
+                FnPtr,
+                UnsafeBinder,
+                Placeholder,
+                Coroutine,
+                CoroutineWitness,
+                Dynamic,
+                Closure,
+                CoroutineClosure,
+                Tuple,
+                Bound,
+                Param,
+                Infer,
+                Alias,
+                Pat,
+                Foreign
+            )?;
+
+            writeln!(fmt, "GenericArgs interner: #{}", self.interners.args.len())?;
+            writeln!(fmt, "Region interner: #{}", self.interners.region.len())?;
+            writeln!(fmt, "Const Allocation interner: #{}", self.interners.const_allocation.len())?;
+            writeln!(fmt, "Layout interner: #{}", self.interners.layout.len())?;
+
+            Ok(())
+        })
     }
 }
 
@@ -2558,7 +2565,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name`
     /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`.
     pub fn trait_may_define_assoc_item(self, trait_def_id: DefId, assoc_name: Ident) -> bool {
-        self.supertrait_def_ids(trait_def_id).any(|trait_did| {
+        elaborate::supertrait_def_ids(self, trait_def_id).any(|trait_did| {
             self.associated_items(trait_did)
                 .filter_by_name_unhygienic(assoc_name.name)
                 .any(|item| self.hygienic_eq(assoc_name, item.ident(self), trait_did))
@@ -2579,14 +2586,6 @@ impl<'tcx> TyCtxt<'tcx> {
         })
     }
 
-    /// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally)
-    /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used
-    /// to identify which traits may define a given associated type to help avoid cycle errors,
-    /// and to make size estimates for vtable layout computation.
-    pub fn supertrait_def_ids(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
-        rustc_type_ir::elaborate::supertrait_def_ids(self, trait_def_id)
-    }
-
     /// Given a closure signature, returns an equivalent fn signature. Detuples
     /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then
     /// you would get a `fn(u32, i32)`.
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 77745599afb..b4b66a8133a 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -9,7 +9,7 @@ use rustc_errors::{
 };
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{self as hir, LangItem, PredicateOrigin, WherePredicateKind};
+use rustc_hir::{self as hir, AmbigArg, LangItem, PredicateOrigin, WherePredicateKind};
 use rustc_span::{BytePos, Span};
 use rustc_type_ir::TyKind::*;
 
@@ -336,7 +336,7 @@ pub fn suggest_constraining_type_params<'a>(
             .collect();
 
         constraints
-            .retain(|(_, def_id, _)| def_id.map_or(true, |def| !bound_trait_defs.contains(&def)));
+            .retain(|(_, def_id, _)| def_id.is_none_or(|def| !bound_trait_defs.contains(&def)));
 
         if constraints.is_empty() {
             continue;
@@ -570,18 +570,18 @@ pub fn suggest_constraining_type_params<'a>(
 pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
 
 impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
-    fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+    fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
         match ty.kind {
-            hir::TyKind::TraitObject(
-                _,
-                hir::Lifetime {
+            hir::TyKind::TraitObject(_, tagged_ptr)
+                if let hir::Lifetime {
                     res:
                         hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
                     ..
-                },
-                _,
-            )
-            | hir::TyKind::OpaqueDef(..) => self.0.push(ty),
+                } = tagged_ptr.pointer() =>
+            {
+                self.0.push(ty.as_unambig_ty())
+            }
+            hir::TyKind::OpaqueDef(..) => self.0.push(ty.as_unambig_ty()),
             _ => {}
         }
         hir::intravisit::walk_ty(self, ty);
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index e4ded2c30f5..b7a648aae3f 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -328,7 +328,7 @@ impl<'tcx> InstanceKind<'tcx> {
             // We include enums without destructors to allow, say, optimizing
             // drops of `Option::None` before LTO. We also respect the intent of
             // `#[inline]` on `Drop::drop` implementations.
-            return ty.ty_adt_def().map_or(true, |adt_def| {
+            return ty.ty_adt_def().is_none_or(|adt_def| {
                 match *self {
                     ty::InstanceKind::DropGlue(..) => adt_def.destructor(tcx).map(|dtor| dtor.did),
                     ty::InstanceKind::AsyncDropGlueCtorShim(..) => {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 1e67cdfc32a..0d41a1d7dbf 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -231,6 +231,7 @@ impl fmt::Display for ValidityRequirement {
 pub enum LayoutError<'tcx> {
     Unknown(Ty<'tcx>),
     SizeOverflow(Ty<'tcx>),
+    TooGeneric(Ty<'tcx>),
     NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
     ReferencesError(ErrorGuaranteed),
     Cycle(ErrorGuaranteed),
@@ -244,6 +245,7 @@ impl<'tcx> LayoutError<'tcx> {
         match self {
             Unknown(_) => middle_unknown_layout,
             SizeOverflow(_) => middle_values_too_big,
+            TooGeneric(_) => middle_too_generic,
             NormalizationFailure(_, _) => middle_cannot_be_normalized,
             Cycle(_) => middle_cycle,
             ReferencesError(_) => middle_layout_references_error,
@@ -257,6 +259,7 @@ impl<'tcx> LayoutError<'tcx> {
         match self {
             Unknown(ty) => E::Unknown { ty },
             SizeOverflow(ty) => E::Overflow { ty },
+            TooGeneric(ty) => E::TooGeneric { ty },
             NormalizationFailure(ty, e) => {
                 E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() }
             }
@@ -272,6 +275,9 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"),
+            LayoutError::TooGeneric(ty) => {
+                write!(f, "`{ty}` does not have a fixed size")
+            }
             LayoutError::SizeOverflow(ty) => {
                 write!(f, "values of the type `{ty}` are too big for the target architecture")
             }
@@ -350,10 +356,11 @@ impl<'tcx> SizeSkeleton<'tcx> {
                     return Err(tcx.arena.alloc(LayoutError::Unknown(ty)));
                 }
             }
-            Err(err @ LayoutError::Unknown(_)) => err,
+            Err(err @ LayoutError::TooGeneric(_)) => err,
             // We can't extract SizeSkeleton info from other layout errors
             Err(
                 e @ LayoutError::Cycle(_)
+                | e @ LayoutError::Unknown(_)
                 | e @ LayoutError::SizeOverflow(_)
                 | e @ LayoutError::NormalizationFailure(..)
                 | e @ LayoutError::ReferencesError(_),
@@ -413,10 +420,9 @@ impl<'tcx> SizeSkeleton<'tcx> {
                             // Alignment is unchanged by arrays.
                             return Ok(SizeSkeleton::Known(Size::from_bytes(size), a));
                         }
-                        Err(tcx.arena.alloc(LayoutError::Unknown(ty)))
+                        Err(err)
                     }
-                    SizeSkeleton::Pointer { .. } => Err(err),
-                    SizeSkeleton::Generic(_) => Err(tcx.arena.alloc(LayoutError::Unknown(ty))),
+                    SizeSkeleton::Pointer { .. } | SizeSkeleton::Generic(_) => Err(err),
                 }
             }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ca70ae794c5..8cd632790a8 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1596,6 +1596,15 @@ impl<'tcx> TyCtxt<'tcx> {
         Some(Ident::new(def, span))
     }
 
+    /// Look up the name and span of a definition.
+    ///
+    /// See [`item_name`][Self::item_name] for more information.
+    pub fn item_ident(self, def_id: DefId) -> Ident {
+        self.opt_item_ident(def_id).unwrap_or_else(|| {
+            bug!("item_ident: no name for {:?}", self.def_path(def_id));
+        })
+    }
+
     pub fn opt_associated_item(self, def_id: DefId) -> Option<AssocItem> {
         if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
             Some(self.associated_item(def_id))
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index bf37ae05c82..a9a47c87a38 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1894,11 +1894,11 @@ impl<'tcx> Ty<'tcx> {
 
             ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false,
 
-            ty::Tuple(tys) => tys.last().map_or(true, |ty| ty.is_trivially_sized(tcx)),
+            ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.is_trivially_sized(tcx)),
 
             ty::Adt(def, args) => def
                 .sized_constraint(tcx)
-                .map_or(true, |ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)),
+                .is_none_or(|ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)),
 
             ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false,
 
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 75893da0e58..7d5e5c2e823 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -20,6 +20,7 @@ use tracing::{debug, instrument};
 
 use super::TypingEnv;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use crate::mir;
 use crate::query::Providers;
 use crate::ty::fold::fold_regions;
 use crate::ty::layout::{FloatExt, IntegerExt};
@@ -1183,18 +1184,18 @@ impl<'tcx> Ty<'tcx> {
 
     /// Returns the maximum value for the given numeric type (including `char`s)
     /// or returns `None` if the type is not numeric.
-    pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> {
+    pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<mir::Const<'tcx>> {
         let typing_env = TypingEnv::fully_monomorphized();
         self.numeric_min_and_max_as_bits(tcx)
-            .map(|(_, max)| ty::Const::from_bits(tcx, max, typing_env, self))
+            .map(|(_, max)| mir::Const::from_bits(tcx, max, typing_env, self))
     }
 
     /// Returns the minimum value for the given numeric type (including `char`s)
     /// or returns `None` if the type is not numeric.
-    pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> {
+    pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<mir::Const<'tcx>> {
         let typing_env = TypingEnv::fully_monomorphized();
         self.numeric_min_and_max_as_bits(tcx)
-            .map(|(min, _)| ty::Const::from_bits(tcx, min, typing_env, self))
+            .map(|(min, _)| mir::Const::from_bits(tcx, min, typing_env, self))
     }
 
     /// Checks whether values of this type `T` have a size known at
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index 09a05104e49..23e2e8ad3d3 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -2,6 +2,7 @@ use std::fmt;
 
 use rustc_ast::Mutability;
 use rustc_macros::HashStable;
+use rustc_type_ir::elaborate;
 
 use crate::mir::interpret::{AllocId, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range};
 use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
@@ -64,7 +65,7 @@ pub(crate) fn vtable_min_entries<'tcx>(
     };
 
     // This includes self in supertraits.
-    for def_id in tcx.supertrait_def_ids(trait_ref.def_id()) {
+    for def_id in elaborate::supertrait_def_ids(tcx, trait_ref.def_id()) {
         count += tcx.own_existential_vtable_entries(def_id).len();
     }
 
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 390909bb0ab..867f8f63969 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -360,7 +360,7 @@ fn find_item_ty_spans(
             if let Res::Def(kind, def_id) = path.res
                 && matches!(kind, DefKind::Enum | DefKind::Struct | DefKind::Union)
             {
-                let check_params = def_id.as_local().map_or(true, |def_id| {
+                let check_params = def_id.as_local().is_none_or(|def_id| {
                     if def_id == needle {
                         spans.push(ty.span);
                     }
@@ -374,7 +374,13 @@ fn find_item_ty_spans(
                         if let hir::GenericArg::Type(ty) = arg
                             && params_in_repr.contains(i as u32)
                         {
-                            find_item_ty_spans(tcx, ty, needle, spans, seen_representable);
+                            find_item_ty_spans(
+                                tcx,
+                                ty.as_unambig_ty(),
+                                needle,
+                                spans,
+                                seen_representable,
+                            );
                         }
                     }
                 }
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index ffdb721fb18..053775b4937 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -25,6 +25,8 @@ mir_build_borrow_of_moved_value = borrow of moved value
     .occurs_because_label = move occurs because `{$name}` has type `{$ty}`, which does not implement the `Copy` trait
     .value_borrowed_label = value borrowed here after move
     .suggestion = borrow this binding in the pattern to avoid moving the value
+    .full_type_name = the full type name has been written to '{$path}'
+    .consider_verbose = consider using `--verbose` to print the full type name to the console
 
 mir_build_call_to_deprecated_safe_fn_requires_unsafe =
     call to deprecated safe function `{$function}` is unsafe and requires unsafe block
diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs
index b944d13fb0d..b21ec8f3083 100644
--- a/compiler/rustc_mir_build/src/builder/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs
@@ -1986,6 +1986,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             return;
         }
 
+        let false_edge_start_block = candidate.subcandidates[0].false_edge_start_block;
         candidate.subcandidates.retain_mut(|candidate| {
             if candidate.extra_data.is_never {
                 candidate.visit_leaves(|subcandidate| {
@@ -2000,8 +2001,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
         });
         if candidate.subcandidates.is_empty() {
-            // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`.
-            candidate.pre_binding_block = Some(self.cfg.start_new_block());
+            // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block` and `otherwise_block`.
+            let next_block = self.cfg.start_new_block();
+            candidate.pre_binding_block = Some(next_block);
+            candidate.otherwise_block = Some(next_block);
+            // In addition, if `candidate` doesn't have `false_edge_start_block`, it should be assigned here.
+            if candidate.false_edge_start_block.is_none() {
+                candidate.false_edge_start_block = false_edge_start_block;
+            }
         }
     }
 
diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs
index 20441530a47..945f02821d9 100644
--- a/compiler/rustc_mir_build/src/builder/scope.rs
+++ b/compiler/rustc_mir_build/src/builder/scope.rs
@@ -785,6 +785,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let local =
                         place.as_local().unwrap_or_else(|| bug!("projection in tail call args"));
 
+                    if !self.local_decls[local].ty.needs_drop(self.tcx, self.typing_env()) {
+                        return None;
+                    }
+
                     Some(DropData { source_info, local, kind: DropKind::Value })
                 }
                 Operand::Constant(_) => None,
@@ -795,6 +799,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             self.scopes.scopes.iter().rev().nth(1).unwrap().region_scope,
             DUMMY_SP,
         );
+        let typing_env = self.typing_env();
         let unwind_drops = &mut self.scopes.unwind_drops;
 
         // the innermost scope contains only the destructors for the tail call arguments
@@ -805,6 +810,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let source_info = drop_data.source_info;
                 let local = drop_data.local;
 
+                if !self.local_decls[local].ty.needs_drop(self.tcx, typing_env) {
+                    continue;
+                }
+
                 match drop_data.kind {
                     DropKind::Value => {
                         // `unwind_to` should drop the value that we're about to
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 5eed9ef798d..995bc311b7c 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -266,7 +266,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for LayoutConstrainedPlaceVisitor<'a, 'tcx> {
             // place, i.e. the expression is a place expression and not a dereference
             // (since dereferencing something leads us to a different place).
             ExprKind::Deref { .. } => {}
-            ref kind if ExprCategory::of(kind).map_or(true, |cat| cat == ExprCategory::Place) => {
+            ref kind if ExprCategory::of(kind).is_none_or(|cat| cat == ExprCategory::Place) => {
                 visit::walk_expr(self, expr);
             }
 
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 83aec9ccdef..1f87bf0dbbb 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -7,7 +7,7 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{self, Ty};
 use rustc_pattern_analysis::errors::Uncovered;
 use rustc_pattern_analysis::rustc::RustcPatCtxt;
-use rustc_span::{Span, Symbol};
+use rustc_span::{Ident, Span, Symbol};
 
 use crate::fluent_generated as fluent;
 
@@ -753,7 +753,7 @@ pub(crate) struct BindingsWithVariantName {
     #[suggestion(code = "{ty_path}::{name}", applicability = "machine-applicable")]
     pub(crate) suggestion: Option<Span>,
     pub(crate) ty_path: String,
-    pub(crate) name: Symbol,
+    pub(crate) name: Ident,
 }
 
 #[derive(LintDiagnostic)]
@@ -790,17 +790,21 @@ pub(crate) struct IrrefutableLetPatternsWhileLet {
 
 #[derive(Diagnostic)]
 #[diag(mir_build_borrow_of_moved_value)]
-pub(crate) struct BorrowOfMovedValue<'tcx> {
+pub(crate) struct BorrowOfMovedValue {
     #[primary_span]
     #[label]
     #[label(mir_build_occurs_because_label)]
     pub(crate) binding_span: Span,
     #[label(mir_build_value_borrowed_label)]
     pub(crate) conflicts_ref: Vec<Span>,
-    pub(crate) name: Symbol,
-    pub(crate) ty: Ty<'tcx>,
+    pub(crate) name: Ident,
+    pub(crate) ty: String,
     #[suggestion(code = "ref ", applicability = "machine-applicable")]
     pub(crate) suggest_borrowing: Option<Span>,
+    #[note(mir_build_full_type_name)]
+    #[note(mir_build_consider_verbose)]
+    pub(crate) has_path: bool,
+    pub(crate) path: String,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 66310867200..e0a1117f905 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -25,7 +25,7 @@ use rustc_session::lint::builtin::{
 };
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::hygiene::DesugaringKind;
-use rustc_span::{Span, sym};
+use rustc_span::{Ident, Span, sym};
 use rustc_trait_selection::infer::InferCtxtExt;
 use tracing::instrument;
 
@@ -795,12 +795,16 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
                 }
             });
             if !conflicts_ref.is_empty() {
+                let mut path = None;
+                let ty = cx.tcx.short_ty_string(ty, &mut path);
                 sess.dcx().emit_err(BorrowOfMovedValue {
                     binding_span: pat.span,
                     conflicts_ref,
-                    name,
+                    name: Ident::new(name, pat.span),
                     ty,
                     suggest_borrowing: Some(pat.span.shrink_to_lo()),
+                    has_path: path.is_some(),
+                    path: path.map(|p| p.display().to_string()).unwrap_or_default(),
                 });
             }
             return;
@@ -904,7 +908,7 @@ fn check_for_bindings_named_same_as_variants(
                     None
                 },
                 ty_path,
-                name,
+                name: Ident::new(name, pat.span),
             },
         )
     }
@@ -1086,6 +1090,12 @@ fn find_fallback_pattern_typo<'tcx>(
                 let vis = cx.tcx.visibility(item.owner_id);
                 if vis.is_accessible_from(parent, cx.tcx) {
                     accessible.push(item_name);
+                    // FIXME: the line below from PR #135310 is a workaround for the ICE in issue
+                    // #135289, where a macro in a dependency can create unreachable patterns in the
+                    // current crate. Path trimming expects diagnostics for a typoed const, but no
+                    // diagnostics are emitted and we ICE. See
+                    // `tests/ui/resolve/const-with-typo-in-pattern-binding-ice-135289.rs` for a
+                    // test that reproduces the ICE if we don't use `with_no_trimmed_paths!`.
                     let path = with_no_trimmed_paths!(cx.tcx.def_path_str(item.owner_id));
                     accessible_path.push(path);
                 } else if name == item_name {
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index e457b514936..9ccabb46c63 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -608,7 +608,7 @@ where
         let before = diffs_before.as_mut().map(next_in_dataflow_order);
 
         assert!(diffs_after.is_empty());
-        assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty));
+        assert!(diffs_before.as_ref().is_none_or(ExactSizeIterator::is_empty));
 
         let terminator = self.cursor.body()[block].terminator();
         let mut terminator_str = String::new();
diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
index 03f11885d58..5bd6fdcf485 100644
--- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
+++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
@@ -116,4 +116,8 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
         // We may have invalidated some `cleanup` blocks so clean those up now.
         super::simplify::remove_dead_blocks(body);
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs
index 24c955c0c78..55694cacd92 100644
--- a/compiler/rustc_mir_transform/src/add_call_guards.rs
+++ b/compiler/rustc_mir_transform/src/add_call_guards.rs
@@ -75,4 +75,8 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
 
         body.basic_blocks_mut().extend(new_blocks);
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
index 12a2fe23b14..87ae2b71654 100644
--- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
+++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
@@ -68,6 +68,10 @@ impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {
 
         patch.apply(body);
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 fn add_move_for_packed_drop<'tcx>(
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 53176eec9bc..1fc788a2dad 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -176,4 +176,8 @@ impl<'tcx> crate::MirPass<'tcx> for AddRetag {
             }
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
index e585e338613..e41f47db545 100644
--- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
+++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
@@ -61,4 +61,8 @@ impl<'tcx> crate::MirPass<'tcx> for Subtyper {
         }
         checker.patcher.apply(body);
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index 1b7c89fd251..d7e22c12394 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -60,6 +60,10 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
             }
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 struct PointerFinder<'a, 'tcx> {
diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index 6a22a58470c..cb844019857 100644
--- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -72,4 +72,8 @@ impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck {
             decl.user_ty = None;
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
index f149bf97cde..27af5818982 100644
--- a/compiler/rustc_mir_transform/src/copy_prop.rs
+++ b/compiler/rustc_mir_transform/src/copy_prop.rs
@@ -56,6 +56,10 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp {
             crate::simplify::remove_unused_definitions(body);
         }
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 /// `SsaLocals` computed equivalence classes between locals considering copy/move assignments.
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index a3715b5d485..3b75be58e43 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1688,6 +1688,10 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
         // Run derefer to fix Derefs that are not in the first place
         deref_finder(tcx, body);
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 /// Looks for any assignments between locals (e.g., `_4 = _5`) that will both be converted to fields
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 8d397f63cc7..adb99a75a9e 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -10,12 +10,12 @@ use rustc_index::bit_set::DenseBitSet;
 use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op};
 
 use crate::coverage::counters::balanced_flow::BalancedFlowGraph;
-use crate::coverage::counters::iter_nodes::IterNodes;
-use crate::coverage::counters::node_flow::{CounterTerm, MergedNodeFlowGraph, NodeCounters};
+use crate::coverage::counters::node_flow::{
+    CounterTerm, NodeCounters, make_node_counters, node_flow_data_for_balanced_graph,
+};
 use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
 
 mod balanced_flow;
-mod iter_nodes;
 mod node_flow;
 mod union_find;
 
@@ -27,12 +27,12 @@ pub(super) fn make_bcb_counters(
 ) -> CoverageCounters {
     // Create the derived graphs that are necessary for subsequent steps.
     let balanced_graph = BalancedFlowGraph::for_graph(graph, |n| !graph[n].is_out_summable);
-    let merged_graph = MergedNodeFlowGraph::for_balanced_graph(&balanced_graph);
+    let node_flow_data = node_flow_data_for_balanced_graph(&balanced_graph);
 
     // Use those graphs to determine which nodes get physical counters, and how
     // to compute the execution counts of other nodes from those counters.
-    let nodes = make_node_counter_priority_list(graph, balanced_graph);
-    let node_counters = merged_graph.make_node_counters(&nodes);
+    let priority_list = make_node_flow_priority_list(graph, balanced_graph);
+    let node_counters = make_node_counters(&node_flow_data, &priority_list);
 
     // Convert the counters into a form suitable for embedding into MIR.
     transcribe_counters(&node_counters, bcb_needs_counter)
@@ -40,7 +40,7 @@ pub(super) fn make_bcb_counters(
 
 /// Arranges the nodes in `balanced_graph` into a list, such that earlier nodes
 /// take priority in being given a counter expression instead of a physical counter.
-fn make_node_counter_priority_list(
+fn make_node_flow_priority_list(
     graph: &CoverageGraph,
     balanced_graph: BalancedFlowGraph<&CoverageGraph>,
 ) -> Vec<BasicCoverageBlock> {
@@ -81,11 +81,11 @@ fn transcribe_counters(
     let mut new = CoverageCounters::with_num_bcbs(bcb_needs_counter.domain_size());
 
     for bcb in bcb_needs_counter.iter() {
-        // Our counter-creation algorithm doesn't guarantee that a counter
-        // expression starts or ends with a positive term, so partition the
+        // Our counter-creation algorithm doesn't guarantee that a node's list
+        // of terms starts or ends with a positive term, so partition the
         // counters into "positive" and "negative" lists for easier handling.
         let (mut pos, mut neg): (Vec<_>, Vec<_>) =
-            old.counter_expr(bcb).iter().partition_map(|&CounterTerm { node, op }| match op {
+            old.counter_terms[bcb].iter().partition_map(|&CounterTerm { node, op }| match op {
                 Op::Add => Either::Left(node),
                 Op::Subtract => Either::Right(node),
             });
diff --git a/compiler/rustc_mir_transform/src/coverage/counters/balanced_flow.rs b/compiler/rustc_mir_transform/src/coverage/counters/balanced_flow.rs
index c108f96a564..4c20722a043 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters/balanced_flow.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters/balanced_flow.rs
@@ -20,8 +20,6 @@ use rustc_data_structures::graph::reversed::ReversedGraph;
 use rustc_index::Idx;
 use rustc_index::bit_set::DenseBitSet;
 
-use crate::coverage::counters::iter_nodes::IterNodes;
-
 /// A view of an underlying graph that has been augmented to have “balanced flow”.
 /// This means that the flow (execution count) of each node is equal to the
 /// sum of its in-edge flows, and also equal to the sum of its out-edge flows.
diff --git a/compiler/rustc_mir_transform/src/coverage/counters/iter_nodes.rs b/compiler/rustc_mir_transform/src/coverage/counters/iter_nodes.rs
deleted file mode 100644
index 9d87f7af1b0..00000000000
--- a/compiler/rustc_mir_transform/src/coverage/counters/iter_nodes.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-use rustc_data_structures::graph;
-use rustc_index::Idx;
-
-pub(crate) trait IterNodes: graph::DirectedGraph {
-    /// Iterates over all nodes of a graph in ascending numeric order.
-    /// Assumes that nodes are densely numbered, i.e. every index in
-    /// `0..num_nodes` is a valid node.
-    ///
-    /// FIXME: Can this just be part of [`graph::DirectedGraph`]?
-    fn iter_nodes(
-        &self,
-    ) -> impl Iterator<Item = Self::Node> + DoubleEndedIterator + ExactSizeIterator {
-        (0..self.num_nodes()).map(<Self::Node as Idx>::new)
-    }
-}
-impl<G: graph::DirectedGraph> IterNodes for G {}
diff --git a/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs b/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs
index 610498c6c0e..9d80b3af42d 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs
@@ -8,18 +8,16 @@
 
 use rustc_data_structures::graph;
 use rustc_index::bit_set::DenseBitSet;
-use rustc_index::{Idx, IndexVec};
+use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_middle::mir::coverage::Op;
-use smallvec::SmallVec;
 
-use crate::coverage::counters::iter_nodes::IterNodes;
-use crate::coverage::counters::union_find::{FrozenUnionFind, UnionFind};
+use crate::coverage::counters::union_find::UnionFind;
 
 #[cfg(test)]
 mod tests;
 
-/// View of some underlying graph, in which each node's successors have been
-/// merged into a single "supernode".
+/// Data representing a view of some underlying graph, in which each node's
+/// successors have been merged into a single "supernode".
 ///
 /// The resulting supernodes have no obvious meaning on their own.
 /// However, merging successor nodes means that a node's out-edges can all
@@ -30,10 +28,10 @@ mod tests;
 /// in the merged graph, it becomes possible to analyze the original node flows
 /// using techniques for analyzing edge flows.
 #[derive(Debug)]
-pub(crate) struct MergedNodeFlowGraph<Node: Idx> {
+pub(crate) struct NodeFlowData<Node: Idx> {
     /// Maps each node to the supernode that contains it, indicated by some
     /// arbitrary "root" node that is part of that supernode.
-    supernodes: FrozenUnionFind<Node>,
+    supernodes: IndexVec<Node, Node>,
     /// For each node, stores the single supernode that all of its successors
     /// have been merged into.
     ///
@@ -42,84 +40,71 @@ pub(crate) struct MergedNodeFlowGraph<Node: Idx> {
     succ_supernodes: IndexVec<Node, Node>,
 }
 
-impl<Node: Idx> MergedNodeFlowGraph<Node> {
-    /// Creates a "merged" view of an underlying graph.
-    ///
-    /// The given graph is assumed to have [“balanced flow”](balanced-flow),
-    /// though it does not necessarily have to be a `BalancedFlowGraph`.
-    ///
-    /// [balanced-flow]: `crate::coverage::counters::balanced_flow::BalancedFlowGraph`.
-    pub(crate) fn for_balanced_graph<G>(graph: G) -> Self
-    where
-        G: graph::DirectedGraph<Node = Node> + graph::Successors,
-    {
-        let mut supernodes = UnionFind::<G::Node>::new(graph.num_nodes());
-
-        // For each node, merge its successors into a single supernode, and
-        // arbitrarily choose one of those successors to represent all of them.
-        let successors = graph
-            .iter_nodes()
-            .map(|node| {
-                graph
-                    .successors(node)
-                    .reduce(|a, b| supernodes.unify(a, b))
-                    .expect("each node in a balanced graph must have at least one out-edge")
-            })
-            .collect::<IndexVec<G::Node, G::Node>>();
-
-        // Now that unification is complete, freeze the supernode forest,
-        // and resolve each arbitrarily-chosen successor to its canonical root.
-        // (This avoids having to explicitly resolve them later.)
-        let supernodes = supernodes.freeze();
-        let succ_supernodes = successors.into_iter().map(|succ| supernodes.find(succ)).collect();
-
-        Self { supernodes, succ_supernodes }
-    }
-
-    fn num_nodes(&self) -> usize {
-        self.succ_supernodes.len()
-    }
+/// Creates a "merged" view of an underlying graph.
+///
+/// The given graph is assumed to have [“balanced flow”](balanced-flow),
+/// though it does not necessarily have to be a `BalancedFlowGraph`.
+///
+/// [balanced-flow]: `crate::coverage::counters::balanced_flow::BalancedFlowGraph`.
+pub(crate) fn node_flow_data_for_balanced_graph<G>(graph: G) -> NodeFlowData<G::Node>
+where
+    G: graph::Successors,
+{
+    let mut supernodes = UnionFind::<G::Node>::new(graph.num_nodes());
+
+    // For each node, merge its successors into a single supernode, and
+    // arbitrarily choose one of those successors to represent all of them.
+    let successors = graph
+        .iter_nodes()
+        .map(|node| {
+            graph
+                .successors(node)
+                .reduce(|a, b| supernodes.unify(a, b))
+                .expect("each node in a balanced graph must have at least one out-edge")
+        })
+        .collect::<IndexVec<G::Node, G::Node>>();
+
+    // Now that unification is complete, take a snapshot of the supernode forest,
+    // and resolve each arbitrarily-chosen successor to its canonical root.
+    // (This avoids having to explicitly resolve them later.)
+    let supernodes = supernodes.snapshot();
+    let succ_supernodes = successors.into_iter().map(|succ| supernodes[succ]).collect();
+
+    NodeFlowData { supernodes, succ_supernodes }
+}
 
-    fn is_supernode(&self, node: Node) -> bool {
-        self.supernodes.find(node) == node
+/// Uses the graph information in `node_flow_data`, together with a given
+/// permutation of all nodes in the graph, to create physical counters and
+/// counter expressions for each node in the underlying graph.
+///
+/// The given list must contain exactly one copy of each node in the
+/// underlying balanced-flow graph. The order of nodes is used as a hint to
+/// influence counter allocation:
+/// - Earlier nodes are more likely to receive counter expressions.
+/// - Later nodes are more likely to receive physical counters.
+pub(crate) fn make_node_counters<Node: Idx>(
+    node_flow_data: &NodeFlowData<Node>,
+    priority_list: &[Node],
+) -> NodeCounters<Node> {
+    let mut builder = SpantreeBuilder::new(node_flow_data);
+
+    for &node in priority_list {
+        builder.visit_node(node);
     }
 
-    /// Using the information in this merged graph, together with a given
-    /// permutation of all nodes in the graph, to create physical counters and
-    /// counter expressions for each node in the underlying graph.
-    ///
-    /// The given list must contain exactly one copy of each node in the
-    /// underlying balanced-flow graph. The order of nodes is used as a hint to
-    /// influence counter allocation:
-    /// - Earlier nodes are more likely to receive counter expressions.
-    /// - Later nodes are more likely to receive physical counters.
-    pub(crate) fn make_node_counters(&self, all_nodes_permutation: &[Node]) -> NodeCounters<Node> {
-        let mut builder = SpantreeBuilder::new(self);
-
-        for &node in all_nodes_permutation {
-            builder.visit_node(node);
-        }
-
-        NodeCounters { counter_exprs: builder.finish() }
-    }
+    NodeCounters { counter_terms: builder.finish() }
 }
 
 /// End result of allocating physical counters and counter expressions for the
 /// nodes of a graph.
 #[derive(Debug)]
 pub(crate) struct NodeCounters<Node: Idx> {
-    counter_exprs: IndexVec<Node, CounterExprVec<Node>>,
-}
-
-impl<Node: Idx> NodeCounters<Node> {
     /// For the given node, returns the finished list of terms that represent
     /// its physical counter or counter expression. Always non-empty.
     ///
-    /// If a node was given a physical counter, its "expression" will contain
+    /// If a node was given a physical counter, the term list will contain
     /// that counter as its sole element.
-    pub(crate) fn counter_expr(&self, this: Node) -> &[CounterTerm<Node>] {
-        self.counter_exprs[this].as_slice()
-    }
+    pub(crate) counter_terms: IndexVec<Node, Vec<CounterTerm<Node>>>,
 }
 
 #[derive(Debug)]
@@ -146,12 +131,11 @@ pub(crate) struct CounterTerm<Node> {
     pub(crate) node: Node,
 }
 
-/// Stores the list of counter terms that make up a node's counter expression.
-type CounterExprVec<Node> = SmallVec<[CounterTerm<Node>; 2]>;
-
 #[derive(Debug)]
 struct SpantreeBuilder<'a, Node: Idx> {
-    graph: &'a MergedNodeFlowGraph<Node>,
+    supernodes: &'a IndexSlice<Node, Node>,
+    succ_supernodes: &'a IndexSlice<Node, Node>,
+
     is_unvisited: DenseBitSet<Node>,
     /// Links supernodes to each other, gradually forming a spanning tree of
     /// the merged-flow graph.
@@ -163,26 +147,32 @@ struct SpantreeBuilder<'a, Node: Idx> {
     yank_buffer: Vec<Node>,
     /// An in-progress counter expression for each node. Each expression is
     /// initially empty, and will be filled in as relevant nodes are visited.
-    counter_exprs: IndexVec<Node, CounterExprVec<Node>>,
+    counter_terms: IndexVec<Node, Vec<CounterTerm<Node>>>,
 }
 
 impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
-    fn new(graph: &'a MergedNodeFlowGraph<Node>) -> Self {
-        let num_nodes = graph.num_nodes();
+    fn new(node_flow_data: &'a NodeFlowData<Node>) -> Self {
+        let NodeFlowData { supernodes, succ_supernodes } = node_flow_data;
+        let num_nodes = supernodes.len();
         Self {
-            graph,
+            supernodes,
+            succ_supernodes,
             is_unvisited: DenseBitSet::new_filled(num_nodes),
             span_edges: IndexVec::from_fn_n(|_| None, num_nodes),
             yank_buffer: vec![],
-            counter_exprs: IndexVec::from_fn_n(|_| SmallVec::new(), num_nodes),
+            counter_terms: IndexVec::from_fn_n(|_| vec![], num_nodes),
         }
     }
 
+    fn is_supernode(&self, node: Node) -> bool {
+        self.supernodes[node] == node
+    }
+
     /// Given a supernode, finds the supernode that is the "root" of its
     /// spantree component. Two nodes that have the same spantree root are
     /// connected in the spantree.
     fn spantree_root(&self, this: Node) -> Node {
-        debug_assert!(self.graph.is_supernode(this));
+        debug_assert!(self.is_supernode(this));
 
         match self.span_edges[this] {
             None => this,
@@ -193,7 +183,7 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
     /// Rotates edges in the spantree so that `this` is the root of its
     /// spantree component.
     fn yank_to_spantree_root(&mut self, this: Node) {
-        debug_assert!(self.graph.is_supernode(this));
+        debug_assert!(self.is_supernode(this));
 
         // The rotation is done iteratively, by first traversing from `this` to
         // its root and storing the path in a buffer, and then traversing the
@@ -235,12 +225,12 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
 
         // Get the supernode containing `this`, and make it the root of its
         // component of the spantree.
-        let this_supernode = self.graph.supernodes.find(this);
+        let this_supernode = self.supernodes[this];
         self.yank_to_spantree_root(this_supernode);
 
         // Get the supernode containing all of this's successors.
-        let succ_supernode = self.graph.succ_supernodes[this];
-        debug_assert!(self.graph.is_supernode(succ_supernode));
+        let succ_supernode = self.succ_supernodes[this];
+        debug_assert!(self.is_supernode(succ_supernode));
 
         // If two supernodes are already connected in the spantree, they will
         // have the same spantree root. (Each supernode is connected to itself.)
@@ -268,8 +258,8 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
             // `this_supernode`.
 
             // Instead of setting `this.measure = true` as in the original paper,
-            // we just add the node's ID to its own "expression".
-            self.counter_exprs[this].push(CounterTerm { node: this, op: Op::Add });
+            // we just add the node's ID to its own list of terms.
+            self.counter_terms[this].push(CounterTerm { node: this, op: Op::Add });
 
             // Walk the spantree from `this.successor` back to `this`. For each
             // spantree edge along the way, add this node's physical counter to
@@ -279,7 +269,7 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
                 let &SpantreeEdge { is_reversed, claiming_node, span_parent } =
                     self.span_edges[curr].as_ref().unwrap();
                 let op = if is_reversed { Op::Subtract } else { Op::Add };
-                self.counter_exprs[claiming_node].push(CounterTerm { node: this, op });
+                self.counter_terms[claiming_node].push(CounterTerm { node: this, op });
 
                 curr = span_parent;
             }
@@ -288,19 +278,20 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
 
     /// Asserts that all nodes have been visited, and returns the computed
     /// counter expressions (made up of physical counters) for each node.
-    fn finish(self) -> IndexVec<Node, CounterExprVec<Node>> {
-        let Self { graph, is_unvisited, span_edges, yank_buffer: _, counter_exprs } = self;
+    fn finish(self) -> IndexVec<Node, Vec<CounterTerm<Node>>> {
+        let Self { ref span_edges, ref is_unvisited, ref counter_terms, .. } = self;
         assert!(is_unvisited.is_empty(), "some nodes were never visited: {is_unvisited:?}");
         debug_assert!(
             span_edges
                 .iter_enumerated()
-                .all(|(node, span_edge)| { span_edge.is_some() <= graph.is_supernode(node) }),
+                .all(|(node, span_edge)| { span_edge.is_some() <= self.is_supernode(node) }),
             "only supernodes can have a span edge",
         );
         debug_assert!(
-            counter_exprs.iter().all(|expr| !expr.is_empty()),
-            "after visiting all nodes, every node should have a non-empty expression",
+            counter_terms.iter().all(|terms| !terms.is_empty()),
+            "after visiting all nodes, every node should have at least one term",
         );
-        counter_exprs
+
+        self.counter_terms
     }
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/counters/node_flow/tests.rs b/compiler/rustc_mir_transform/src/coverage/counters/node_flow/tests.rs
index 9e7f754523d..b509a14514b 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters/node_flow/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters/node_flow/tests.rs
@@ -4,10 +4,12 @@ use rustc_data_structures::graph::vec_graph::VecGraph;
 use rustc_index::Idx;
 use rustc_middle::mir::coverage::Op;
 
-use super::{CounterTerm, MergedNodeFlowGraph, NodeCounters};
+use crate::coverage::counters::node_flow::{
+    CounterTerm, NodeCounters, NodeFlowData, make_node_counters, node_flow_data_for_balanced_graph,
+};
 
-fn merged_node_flow_graph<G: graph::Successors>(graph: G) -> MergedNodeFlowGraph<G::Node> {
-    MergedNodeFlowGraph::for_balanced_graph(graph)
+fn node_flow_data<G: graph::Successors>(graph: G) -> NodeFlowData<G::Node> {
+    node_flow_data_for_balanced_graph(graph)
 }
 
 fn make_graph<Node: Idx + Ord>(num_nodes: usize, edge_pairs: Vec<(Node, Node)>) -> VecGraph<Node> {
@@ -30,8 +32,8 @@ fn example_driver() {
         (4, 0),
     ]);
 
-    let merged = merged_node_flow_graph(&graph);
-    let counters = merged.make_node_counters(&[3, 1, 2, 0, 4]);
+    let node_flow_data = node_flow_data(&graph);
+    let counters = make_node_counters(&node_flow_data, &[3, 1, 2, 0, 4]);
 
     assert_eq!(format_counter_expressions(&counters), &[
         // (comment to force vertical formatting for clarity)
@@ -53,12 +55,12 @@ fn format_counter_expressions<Node: Idx>(counters: &NodeCounters<Node>) -> Vec<S
     };
 
     counters
-        .counter_exprs
+        .counter_terms
         .indices()
         .map(|node| {
-            let mut expr = counters.counter_expr(node).iter().collect::<Vec<_>>();
-            expr.sort_by_key(|item| item.node.index());
-            format!("[{node:?}]: {}", expr.into_iter().map(format_item).join(" "))
+            let mut terms = counters.counter_terms[node].iter().collect::<Vec<_>>();
+            terms.sort_by_key(|item| item.node.index());
+            format!("[{node:?}]: {}", terms.into_iter().map(format_item).join(" "))
         })
         .collect()
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/counters/union_find.rs b/compiler/rustc_mir_transform/src/coverage/counters/union_find.rs
index 2da4f5f5fce..a826a953fa6 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters/union_find.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters/union_find.rs
@@ -88,29 +88,9 @@ impl<Key: Idx> UnionFind<Key> {
         a
     }
 
-    /// Creates a snapshot of this disjoint-set forest that can no longer be
-    /// mutated, but can be queried without mutation.
-    pub(crate) fn freeze(&mut self) -> FrozenUnionFind<Key> {
-        // Just resolve each key to its actual root.
-        let roots = self.table.indices().map(|key| self.find(key)).collect();
-        FrozenUnionFind { roots }
-    }
-}
-
-/// Snapshot of a disjoint-set forest that can no longer be mutated, but can be
-/// queried in O(1) time without mutation.
-///
-/// This is really just a wrapper around a direct mapping from keys to roots,
-/// but with a [`Self::find`] method that resembles [`UnionFind::find`].
-#[derive(Debug)]
-pub(crate) struct FrozenUnionFind<Key: Idx> {
-    roots: IndexVec<Key, Key>,
-}
-
-impl<Key: Idx> FrozenUnionFind<Key> {
-    /// Returns the "root" key of the disjoint-set containing the given key.
-    /// If two keys have the same root, they belong to the same set.
-    pub(crate) fn find(&self, key: Key) -> Key {
-        self.roots[key]
+    /// Takes a "snapshot" of the current state of this disjoint-set forest, in
+    /// the form of a vector that directly maps each key to its current root.
+    pub(crate) fn snapshot(&mut self) -> IndexVec<Key, Key> {
+        self.table.indices().map(|key| self.find(key)).collect()
     }
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 25dc7f31227..392b54c8d81 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -135,7 +135,7 @@ impl CoverageGraph {
                 bb_to_bcb[bb] = Some(bcb);
             }
 
-            let is_out_summable = basic_blocks.last().map_or(false, |&bb| {
+            let is_out_summable = basic_blocks.last().is_some_and(|&bb| {
                 bcb_filtered_successors(mir_body[bb].terminator()).is_out_summable()
             });
             let bcb_data = BasicCoverageBlockData { basic_blocks, is_out_summable };
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 19568735df7..15487d05a30 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -61,6 +61,10 @@ impl<'tcx> crate::MirPass<'tcx> for InstrumentCoverage {
 
         instrument_function_for_coverage(tcx, mir_body);
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
@@ -180,7 +184,12 @@ fn create_mappings(
     ));
 
     for (decision, branches) in mcdc_mappings {
-        let num_conditions = branches.len() as u16;
+        // FIXME(#134497): Previously it was possible for some of these branch
+        // conversions to fail, in which case the remaining branches in the
+        // decision would be degraded to plain `MappingKind::Branch`.
+        // The changes in #134497 made that failure impossible, because the
+        // fallible step was deferred to codegen. But the corresponding code
+        // in codegen wasn't updated to detect the need for a degrade step.
         let conditions = branches
             .into_iter()
             .map(
@@ -206,24 +215,13 @@ fn create_mappings(
             )
             .collect::<Vec<_>>();
 
-        if conditions.len() == num_conditions as usize {
-            // LLVM requires end index for counter mapping regions.
-            let kind = MappingKind::MCDCDecision(DecisionInfo {
-                bitmap_idx: (decision.bitmap_idx + decision.num_test_vectors) as u32,
-                num_conditions,
-            });
-            let span = decision.span;
-            mappings.extend(std::iter::once(Mapping { kind, span }).chain(conditions.into_iter()));
-        } else {
-            mappings.extend(conditions.into_iter().map(|mapping| {
-                let MappingKind::MCDCBranch { true_term, false_term, mcdc_params: _ } =
-                    mapping.kind
-                else {
-                    unreachable!("all mappings here are MCDCBranch as shown above");
-                };
-                Mapping { kind: MappingKind::Branch { true_term, false_term }, span: mapping.span }
-            }))
-        }
+        // LLVM requires end index for counter mapping regions.
+        let kind = MappingKind::MCDCDecision(DecisionInfo {
+            bitmap_idx: (decision.bitmap_idx + decision.num_test_vectors) as u32,
+            num_conditions: u16::try_from(conditions.len()).unwrap(),
+        });
+        let span = decision.span;
+        mappings.extend(std::iter::once(Mapping { kind, span }).chain(conditions.into_iter()));
     }
 
     mappings
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index 3e7cf8541c2..5e7b46182dc 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -87,15 +87,9 @@ fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
 fn coverage_ids_info<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance_def: ty::InstanceKind<'tcx>,
-) -> CoverageIdsInfo {
+) -> Option<CoverageIdsInfo> {
     let mir_body = tcx.instance_mir(instance_def);
-
-    let Some(fn_cov_info) = mir_body.function_coverage_info.as_deref() else {
-        return CoverageIdsInfo {
-            counters_seen: DenseBitSet::new_empty(0),
-            zero_expressions: DenseBitSet::new_empty(0),
-        };
-    };
+    let fn_cov_info = mir_body.function_coverage_info.as_deref()?;
 
     let mut counters_seen = DenseBitSet::new_empty(fn_cov_info.num_counters);
     let mut expressions_seen = DenseBitSet::new_filled(fn_cov_info.expressions.len());
@@ -129,7 +123,7 @@ fn coverage_ids_info<'tcx>(
     let zero_expressions =
         identify_zero_expressions(fn_cov_info, &counters_seen, &expressions_seen);
 
-    CoverageIdsInfo { counters_seen, zero_expressions }
+    Some(CoverageIdsInfo { counters_seen, zero_expressions })
 }
 
 fn all_coverage_in_mir_body<'a, 'tcx>(
diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
index 8fce856687c..4f45d9588a8 100644
--- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs
+++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
@@ -69,7 +69,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     // Don't do any inference if codegen optimizations are disabled and also MIR inlining is not
     // enabled. This ensures that we do inference even if someone only passes -Zinline-mir,
     // which is less confusing than having to also enable -Copt-level=1.
-    let inliner_will_run = pm::should_run_pass(tcx, &inline::Inline)
+    let inliner_will_run = pm::should_run_pass(tcx, &inline::Inline, pm::Optimizations::Allowed)
         || inline::ForceInline::should_run_pass_for_callee(tcx, def_id.to_def_id());
     if matches!(tcx.sess.opts.optimize, OptLevel::No) && !inliner_will_run {
         return false;
diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs
index bd58b1b6689..d0b313e149a 100644
--- a/compiler/rustc_mir_transform/src/ctfe_limit.rs
+++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs
@@ -36,6 +36,10 @@ impl<'tcx> crate::MirPass<'tcx> for CtfeLimit {
             );
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 fn has_back_edge(
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 51af77778af..8879e029346 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -71,6 +71,10 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
         let mut patch = visitor.patch;
         debug_span!("patch").in_scope(|| patch.visit_body_preserves_cfg(body));
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 // Note: Currently, places that have their reference taken cannot be tracked. Although this would
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 434e921d439..eea2b0990d7 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -147,4 +147,8 @@ impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         eliminate(tcx, body);
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
index 26b28c8c487..63257df66fb 100644
--- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
+++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
@@ -31,6 +31,10 @@ impl<'tcx> crate::MirPass<'tcx> for DeduplicateBlocks {
             simplify_cfg(body);
         }
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 struct OptApplier<'tcx> {
diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs
index ad7ccef4976..a54bdaa4075 100644
--- a/compiler/rustc_mir_transform/src/deref_separator.rs
+++ b/compiler/rustc_mir_transform/src/deref_separator.rs
@@ -81,4 +81,8 @@ impl<'tcx> crate::MirPass<'tcx> for Derefer {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         deref_finder(tcx, body);
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index b4f9f1f08ef..41de1b58b91 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -240,6 +240,10 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
 
         trace!(round_count);
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 #[derive(Debug, Default)]
diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs
index 5dd84975b88..e4fcbaa483d 100644
--- a/compiler/rustc_mir_transform/src/dump_mir.rs
+++ b/compiler/rustc_mir_transform/src/dump_mir.rs
@@ -15,6 +15,10 @@ impl<'tcx> crate::MirPass<'tcx> for Marker {
     }
 
     fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> {
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index 91e1395e764..eb335a1e4a7 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -227,6 +227,10 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
             simplify_cfg(body);
         }
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 #[derive(Debug)]
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index d6ecadbfe29..6d3b5d9851b 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -150,4 +150,8 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
             }
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index 988f1a25561..cb869160c80 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -88,6 +88,10 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops {
         elaborate_patch.apply(body);
         deref_finder(tcx, body);
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 /// Records unwind edges which are known to be unreachable, because they are in `drop` terminators
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index a2fd46043ca..29698b0c2e4 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -5,7 +5,7 @@ use rustc_middle::mir::AssertKind;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::{self, Lint};
 use rustc_span::def_id::DefId;
-use rustc_span::{Span, Symbol};
+use rustc_span::{Ident, Span, Symbol};
 
 use crate::fluent_generated as fluent;
 
@@ -114,7 +114,7 @@ pub(crate) struct FnItemRef {
     #[suggestion(code = "{sugg}", applicability = "unspecified")]
     pub span: Span,
     pub sugg: String,
-    pub ident: String,
+    pub ident: Ident,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index fb21bf9977f..7e88925b2e1 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -168,7 +168,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
                 s
             }
         };
-        let ident = self.tcx.item_name(fn_id).to_ident_string();
+        let ident = self.tcx.item_ident(fn_id);
         let ty_params = fn_args.types().map(|ty| format!("{ty}"));
         let const_params = fn_args.consts().map(|c| format!("{c}"));
         let params = ty_params.chain(const_params).join(", ");
@@ -177,7 +177,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
         let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
         let sugg = format!(
             "{} as {}{}fn({}{}){}",
-            if params.is_empty() { ident.clone() } else { format!("{ident}::<{params}>") },
+            if params.is_empty() { ident.to_string() } else { format!("{ident}::<{params}>") },
             unsafety,
             abi,
             vec!["_"; num_args].join(", "),
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index cb03b422d9e..1c2c82d4cd5 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -163,6 +163,10 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
         // statements.
         StorageRemover { tcx, reused_locals: state.reused_locals }.visit_body_preserves_cfg(body);
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 newtype_index! {
@@ -1174,11 +1178,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             ) if let ty::Slice(..) = to.builtin_deref(true).unwrap().kind()
                 && let ty::Array(_, len) = from.builtin_deref(true).unwrap().kind() =>
             {
-                return self.insert_constant(Const::from_ty_const(
-                    *len,
-                    self.tcx.types.usize,
-                    self.tcx,
-                ));
+                return self.insert_constant(Const::Ty(self.tcx.types.usize, *len));
             }
             _ => Value::UnaryOp(op, arg_index),
         };
@@ -1488,11 +1488,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         // Trivial case: we are fetching a statically known length.
         let place_ty = place.ty(self.local_decls, self.tcx).ty;
         if let ty::Array(_, len) = place_ty.kind() {
-            return self.insert_constant(Const::from_ty_const(
-                *len,
-                self.tcx.types.usize,
-                self.tcx,
-            ));
+            return self.insert_constant(Const::Ty(self.tcx.types.usize, *len));
         }
 
         let mut inner = self.simplify_place_value(place, location)?;
@@ -1514,11 +1510,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             && let Some(to) = to.builtin_deref(true)
             && let ty::Slice(..) = to.kind()
         {
-            return self.insert_constant(Const::from_ty_const(
-                *len,
-                self.tcx.types.usize,
-                self.tcx,
-            ));
+            return self.insert_constant(Const::Ty(self.tcx.types.usize, *len));
         }
 
         // Fallback: a symbolic `Len`.
diff --git a/compiler/rustc_mir_transform/src/impossible_predicates.rs b/compiler/rustc_mir_transform/src/impossible_predicates.rs
index ba8389bbe2f..86e2bf6cb3c 100644
--- a/compiler/rustc_mir_transform/src/impossible_predicates.rs
+++ b/compiler/rustc_mir_transform/src/impossible_predicates.rs
@@ -53,4 +53,8 @@ impl<'tcx> MirPass<'tcx> for ImpossiblePredicates {
             body.local_decls.raw.truncate(body.arg_count + 1);
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 2052e28325c..95aeccfdda6 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -66,6 +66,10 @@ impl<'tcx> crate::MirPass<'tcx> for Inline {
             deref_finder(tcx, body);
         }
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 pub struct ForceInline;
@@ -85,6 +89,10 @@ impl<'tcx> crate::MirPass<'tcx> for ForceInline {
         false
     }
 
+    fn is_required(&self) -> bool {
+        true
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let span = trace_span!("force_inline", body = %tcx.def_path_str(body.source.def_id()));
         let _guard = span.enter();
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 5a36519e6a3..4b9ebd40b85 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -62,6 +62,10 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
             simplify_duplicate_switch_targets(block.terminator.as_mut().unwrap());
         }
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 struct InstSimplifyContext<'a, 'tcx> {
@@ -167,7 +171,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
         if let Rvalue::Len(ref place) = *rvalue {
             let place_ty = place.ty(self.local_decls, self.tcx).ty;
             if let ty::Array(_, len) = *place_ty.kind() {
-                let const_ = Const::from_ty_const(len, self.tcx.types.usize, self.tcx);
+                let const_ = Const::Ty(self.tcx.types.usize, len);
                 let constant = ConstOperand { span: DUMMY_SP, const_, user_ty: None };
                 *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
             }
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index c73a03489c5..17084eca6e3 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -105,6 +105,10 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
         }
         OpportunitySet::new(body, opportunities).apply(body);
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 #[derive(Debug)]
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index 490e7dd8f7e..e201763468b 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -200,6 +200,10 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
             });
         }
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 impl EnumSizeOpt {
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index d1bacf1f598..2dc55e3614e 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -388,6 +388,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
             &Lint(sanity_check::SanityCheck),
         ],
         None,
+        pm::Optimizations::Allowed,
     );
     tcx.alloc_steal_mir(body)
 }
@@ -440,6 +441,7 @@ fn mir_promoted(
         &mut body,
         &[&promote_pass, &simplify::SimplifyCfg::PromoteConsts, &coverage::InstrumentCoverage],
         Some(MirPhase::Analysis(AnalysisPhase::Initial)),
+        pm::Optimizations::Allowed,
     );
 
     lint_tail_expr_drop_order::run_lint(tcx, def, &body);
@@ -473,7 +475,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
     };
 
     let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const);
-    pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None);
+    pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None, pm::Optimizations::Allowed);
 
     body
 }
@@ -493,7 +495,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
     let is_fn_like = tcx.def_kind(def).is_fn_like();
     if is_fn_like {
         // Do not compute the mir call graph without said call graph actually being used.
-        if pm::should_run_pass(tcx, &inline::Inline)
+        if pm::should_run_pass(tcx, &inline::Inline, pm::Optimizations::Allowed)
             || inline::ForceInline::should_run_pass_for_callee(tcx, def.to_def_id())
         {
             tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id()));
@@ -533,6 +535,7 @@ pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'
                 &Lint(post_drop_elaboration::CheckLiveDrops),
             ],
             None,
+            pm::Optimizations::Allowed,
         );
     }
 
@@ -557,7 +560,13 @@ fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         &deref_separator::Derefer,
     ];
 
-    pm::run_passes(tcx, body, passes, Some(MirPhase::Analysis(AnalysisPhase::PostCleanup)));
+    pm::run_passes(
+        tcx,
+        body,
+        passes,
+        Some(MirPhase::Analysis(AnalysisPhase::PostCleanup)),
+        pm::Optimizations::Allowed,
+    );
 }
 
 /// Returns the sequence of passes that lowers analysis to runtime MIR.
@@ -597,7 +606,13 @@ fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         &simplify::SimplifyCfg::PreOptimizations,
     ];
 
-    pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup)));
+    pm::run_passes(
+        tcx,
+        body,
+        passes,
+        Some(MirPhase::Runtime(RuntimePhase::PostCleanup)),
+        pm::Optimizations::Allowed,
+    );
 
     // Clear this by anticipation. Optimizations and runtime MIR have no reason to look
     // into this information, which is meant for borrowck diagnostics.
@@ -611,6 +626,15 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         WithMinOptLevel(1, x)
     }
 
+    let def_id = body.source.def_id();
+    let optimizations = if tcx.def_kind(def_id).has_codegen_attrs()
+        && tcx.codegen_fn_attrs(def_id).optimize.do_not_optimize()
+    {
+        pm::Optimizations::Suppressed
+    } else {
+        pm::Optimizations::Allowed
+    };
+
     // The main optimizations that we do on MIR.
     pm::run_passes(
         tcx,
@@ -683,6 +707,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             &dump_mir::Marker("PreCodegen"),
         ],
         Some(MirPhase::Runtime(RuntimePhase::Optimized)),
+        optimizations,
     );
 }
 
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 942c6144ea6..9a9f66ed4fd 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -325,4 +325,8 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
             }
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs
index 420661f29c8..aca80e36e33 100644
--- a/compiler/rustc_mir_transform/src/lower_slice_len.rs
+++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs
@@ -26,6 +26,10 @@ impl<'tcx> crate::MirPass<'tcx> for LowerSliceLenCalls {
             lower_slice_len_call(block, slice_len_fn_item_def_id);
         }
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 fn lower_slice_len_call<'tcx>(block: &mut BasicBlockData<'tcx>, slice_len_fn_item_def_id: DefId) {
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index 534ba991780..500116580d5 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -49,6 +49,10 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
             simplify_cfg(body);
         }
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 trait SimplifyMatch<'tcx> {
diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs
index cf5c5f85a9f..f5c57418467 100644
--- a/compiler/rustc_mir_transform/src/mentioned_items.rs
+++ b/compiler/rustc_mir_transform/src/mentioned_items.rs
@@ -27,6 +27,10 @@ impl<'tcx> crate::MirPass<'tcx> for MentionedItems {
         visitor.visit_body(body);
         body.set_mentioned_items(visitor.mentioned_items);
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 // This visitor is carefully in sync with the one in `rustc_monomorphize::collector`. We are
diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
index 6dfa14d6b52..c63bfdcee85 100644
--- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
+++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
@@ -36,4 +36,8 @@ impl<'tcx> crate::MirPass<'tcx> for MultipleReturnTerminators {
 
         simplify::remove_dead_blocks(body)
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
index 35872de3852..965002aae04 100644
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -71,6 +71,10 @@ impl<'tcx> crate::MirPass<'tcx> for RenameReturnPlace {
         // The return place is always mutable.
         ret_decl.mutability = Mutability::Mut;
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 /// MIR that is eligible for the NRVO must fulfill two conditions:
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index c3f0a989ce1..7a8d3ba1ff1 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -90,6 +90,11 @@ pub(super) trait MirPass<'tcx> {
     fn is_mir_dump_enabled(&self) -> bool {
         true
     }
+
+    /// Returns `true` if this pass must be run (i.e. it is required for soundness).
+    /// For passes which are strictly optimizations, this should return `false`.
+    /// If this is `false`, `#[optimize(none)]` will disable the pass.
+    fn is_required(&self) -> bool;
 }
 
 /// Just like `MirPass`, except it cannot mutate `Body`, and MIR dumping is
@@ -134,6 +139,10 @@ where
     fn is_mir_dump_enabled(&self) -> bool {
         false
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 pub(super) struct WithMinOptLevel<T>(pub u32, pub T);
@@ -153,6 +162,19 @@ where
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         self.1.run_pass(tcx, body)
     }
+
+    fn is_required(&self) -> bool {
+        self.1.is_required()
+    }
+}
+
+/// Whether to allow non-[required] optimizations
+///
+/// [required]: MirPass::is_required
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub(crate) enum Optimizations {
+    Suppressed,
+    Allowed,
 }
 
 /// Run the sequence of passes without validating the MIR after each pass. The MIR is still
@@ -163,7 +185,7 @@ pub(super) fn run_passes_no_validate<'tcx>(
     passes: &[&dyn MirPass<'tcx>],
     phase_change: Option<MirPhase>,
 ) {
-    run_passes_inner(tcx, body, passes, phase_change, false);
+    run_passes_inner(tcx, body, passes, phase_change, false, Optimizations::Allowed);
 }
 
 /// The optional `phase_change` is applied after executing all the passes, if present
@@ -172,11 +194,16 @@ pub(super) fn run_passes<'tcx>(
     body: &mut Body<'tcx>,
     passes: &[&dyn MirPass<'tcx>],
     phase_change: Option<MirPhase>,
+    optimizations: Optimizations,
 ) {
-    run_passes_inner(tcx, body, passes, phase_change, true);
+    run_passes_inner(tcx, body, passes, phase_change, true, optimizations);
 }
 
-pub(super) fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool
+pub(super) fn should_run_pass<'tcx, P>(
+    tcx: TyCtxt<'tcx>,
+    pass: &P,
+    optimizations: Optimizations,
+) -> bool
 where
     P: MirPass<'tcx> + ?Sized,
 {
@@ -196,7 +223,8 @@ where
             );
             *polarity
         });
-    overridden.unwrap_or_else(|| pass.is_enabled(tcx.sess))
+    let suppressed = !pass.is_required() && matches!(optimizations, Optimizations::Suppressed);
+    overridden.unwrap_or_else(|| !suppressed && pass.is_enabled(tcx.sess))
 }
 
 fn run_passes_inner<'tcx>(
@@ -205,6 +233,7 @@ fn run_passes_inner<'tcx>(
     passes: &[&dyn MirPass<'tcx>],
     phase_change: Option<MirPhase>,
     validate_each: bool,
+    optimizations: Optimizations,
 ) {
     let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
     trace!(?overridden_passes);
@@ -243,7 +272,7 @@ fn run_passes_inner<'tcx>(
         for pass in passes {
             let name = pass.name();
 
-            if !should_run_pass(tcx, *pass) {
+            if !should_run_pass(tcx, *pass, optimizations) {
                 continue;
             };
 
diff --git a/compiler/rustc_mir_transform/src/post_analysis_normalize.rs b/compiler/rustc_mir_transform/src/post_analysis_normalize.rs
index 3eecf79a7ea..76c2f082c0b 100644
--- a/compiler/rustc_mir_transform/src/post_analysis_normalize.rs
+++ b/compiler/rustc_mir_transform/src/post_analysis_normalize.rs
@@ -15,6 +15,10 @@ impl<'tcx> crate::MirPass<'tcx> for PostAnalysisNormalize {
         let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id());
         PostAnalysisNormalizeVisitor { tcx, typing_env }.visit_body_preserves_cfg(body);
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 struct PostAnalysisNormalizeVisitor<'tcx> {
diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs
index 51abd4da86e..8ccfbe2f194 100644
--- a/compiler/rustc_mir_transform/src/prettify.rs
+++ b/compiler/rustc_mir_transform/src/prettify.rs
@@ -35,6 +35,10 @@ impl<'tcx> crate::MirPass<'tcx> for ReorderBasicBlocks {
 
         permute(body.basic_blocks.as_mut(), &updater.map);
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 /// Rearranges the locals into *use* order.
@@ -85,6 +89,10 @@ impl<'tcx> crate::MirPass<'tcx> for ReorderLocals {
 
         permute(&mut body.local_decls, &updater.map);
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 fn permute<I: rustc_index::Idx + Ord, T>(data: &mut IndexVec<I, T>, map: &IndexSlice<I, I>) {
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 6be95b1f0f1..6aa3343bb6e 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -61,6 +61,10 @@ impl<'tcx> crate::MirPass<'tcx> for PromoteTemps<'tcx> {
         let promoted = promote_candidates(body, tcx, temps, promotable_candidates);
         self.promoted_fragments.set(promoted);
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 /// State of a temporary during collection and promotion.
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index 95b05f94270..368d5340ac3 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -81,6 +81,10 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
         debug!(def_id = ?body.source.def_id());
         while propagate_ssa(tcx, body) {}
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 76a3edfe0be..9cdd52bec7b 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -74,6 +74,10 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
 
         debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed);
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 impl RemoveNoopLandingPads {
diff --git a/compiler/rustc_mir_transform/src/remove_place_mention.rs b/compiler/rustc_mir_transform/src/remove_place_mention.rs
index 71399eb72f0..15fe77d5319 100644
--- a/compiler/rustc_mir_transform/src/remove_place_mention.rs
+++ b/compiler/rustc_mir_transform/src/remove_place_mention.rs
@@ -20,4 +20,8 @@ impl<'tcx> crate::MirPass<'tcx> for RemovePlaceMention {
             })
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
index 3ecb4a8994f..1ae33c00968 100644
--- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs
+++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
@@ -22,4 +22,8 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveStorageMarkers {
             })
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
index e955d8277a4..9044a88295c 100644
--- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -62,6 +62,10 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
             block.terminator_mut().kind = TerminatorKind::Goto { target: *target };
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 fn is_needs_drop_and_init<'tcx>(
diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
index e335051d656..8a8cdafc690 100644
--- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
@@ -38,4 +38,8 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops {
             simplify_cfg(body);
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index 55e5701bd0a..78d94a03867 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -27,6 +27,10 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveZsts {
             replacer.visit_basic_block_data(bb, data);
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 struct Replacer<'a, 'tcx> {
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 4648ec33c93..f7ec0f740d3 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -119,6 +119,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
                         &add_call_guards::CriticalCallEdges,
                     ],
                     Some(MirPhase::Runtime(RuntimePhase::Optimized)),
+                    pm::Optimizations::Allowed,
                 );
 
                 return body;
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 4f312ed2aaa..67070f03ded 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -83,6 +83,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyCfg {
         debug!("SimplifyCfg({:?}) - simplifying {:?}", self.name(), body.source);
         simplify_cfg(body);
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 struct CfgSimplifier<'a, 'tcx> {
@@ -405,6 +409,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyLocals {
             body.local_decls.shrink_to_fit();
         }
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 pub(super) fn remove_unused_definitions<'tcx>(body: &mut Body<'tcx>) {
diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs
index bea3d0d8557..12c3503879f 100644
--- a/compiler/rustc_mir_transform/src/simplify_branches.rs
+++ b/compiler/rustc_mir_transform/src/simplify_branches.rs
@@ -60,4 +60,8 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
             };
         }
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index b6d80173086..c0f25c7ecfe 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -140,6 +140,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral {
             body.basic_blocks_mut()[idx].statements.insert(0, stmt);
         }
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 struct OptimizationFinder<'a, 'tcx> {
diff --git a/compiler/rustc_mir_transform/src/single_use_consts.rs b/compiler/rustc_mir_transform/src/single_use_consts.rs
index 10b3c0ae94f..c5e951eb8b2 100644
--- a/compiler/rustc_mir_transform/src/single_use_consts.rs
+++ b/compiler/rustc_mir_transform/src/single_use_consts.rs
@@ -81,6 +81,10 @@ impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts {
             }
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 #[derive(Copy, Clone, Debug)]
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index d54ea3feab6..92e5c8a9ca4 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -48,6 +48,10 @@ impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates {
             }
         }
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 /// Identify all locals that are not eligible for SROA.
diff --git a/compiler/rustc_mir_transform/src/strip_debuginfo.rs b/compiler/rustc_mir_transform/src/strip_debuginfo.rs
index 438c75726bb..9ede8aa79c4 100644
--- a/compiler/rustc_mir_transform/src/strip_debuginfo.rs
+++ b/compiler/rustc_mir_transform/src/strip_debuginfo.rs
@@ -31,4 +31,8 @@ impl<'tcx> crate::MirPass<'tcx> for StripDebugInfo {
             )
         });
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
index 55dcad0680a..1ff7043ed14 100644
--- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
@@ -208,4 +208,8 @@ impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching {
 
         patch.apply(body);
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs
index 734703ec78b..1e5d9469c03 100644
--- a/compiler/rustc_mir_transform/src/unreachable_prop.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs
@@ -52,6 +52,10 @@ impl crate::MirPass<'_> for UnreachablePropagation {
             body.basic_blocks_mut()[bb].statements.clear();
         }
     }
+
+    fn is_required(&self) -> bool {
+        false
+    }
 }
 
 /// Return whether the current terminator is fully unreachable.
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index b62e34ac08d..026923ad786 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -91,6 +91,10 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
             }
         }
     }
+
+    fn is_required(&self) -> bool {
+        true
+    }
 }
 
 struct CfgChecker<'a, 'tcx> {
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 7b179663430..e08c348a64d 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -110,7 +110,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
 use rustc_middle::mir::mono::{
     CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, Linkage, MonoItem, MonoItemData,
-    Visibility,
+    MonoItemPartitions, Visibility,
 };
 use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths};
 use rustc_middle::ty::{self, InstanceKind, TyCtxt};
@@ -1114,7 +1114,7 @@ where
     }
 }
 
-fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[CodegenUnit<'_>]) {
+fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitions<'_> {
     let collection_strategy = match tcx.sess.opts.unstable_opts.print_mono_items {
         Some(ref s) => {
             let mode = s.to_lowercase();
@@ -1236,7 +1236,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co
         }
     }
 
-    (tcx.arena.alloc(mono_items), codegen_units)
+    MonoItemPartitions { all_mono_items: tcx.arena.alloc(mono_items), codegen_units }
 }
 
 /// Outputs stats about instantiation counts and estimated size, per `MonoItem`'s
@@ -1319,14 +1319,13 @@ fn dump_mono_items_stats<'tcx>(
 pub(crate) fn provide(providers: &mut Providers) {
     providers.collect_and_partition_mono_items = collect_and_partition_mono_items;
 
-    providers.is_codegened_item = |tcx, def_id| {
-        let (all_mono_items, _) = tcx.collect_and_partition_mono_items(());
-        all_mono_items.contains(&def_id)
-    };
+    providers.is_codegened_item =
+        |tcx, def_id| tcx.collect_and_partition_mono_items(()).all_mono_items.contains(&def_id);
 
     providers.codegen_unit = |tcx, name| {
-        let (_, all) = tcx.collect_and_partition_mono_items(());
-        all.iter()
+        tcx.collect_and_partition_mono_items(())
+            .codegen_units
+            .iter()
             .find(|cgu| cgu.name() == name)
             .unwrap_or_else(|| panic!("failed to find cgu with name {name:?}"))
     };
diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml
index f9168112216..451c215566b 100644
--- a/compiler/rustc_next_trait_solver/Cargo.toml
+++ b/compiler/rustc_next_trait_solver/Cargo.toml
@@ -13,7 +13,6 @@ rustc_macros = { path = "../rustc_macros", optional = true }
 rustc_serialize = { path = "../rustc_serialize", optional = true }
 rustc_type_ir = { path = "../rustc_type_ir", default-features = false }
 rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
-smallvec = "1.8.1"
 tracing = "0.1"
 # tidy-alphabetical-end
 
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 8a54a4ece98..62a7c84bc28 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -273,7 +273,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
                         //
                         // For this we set `next_orig_uv` to the next smallest, not yet compressed,
                         // universe of the input.
-                        if next_orig_uv.map_or(true, |curr_next_uv| uv.cannot_name(curr_next_uv)) {
+                        if next_orig_uv.is_none_or(|curr_next_uv| uv.cannot_name(curr_next_uv)) {
                             next_orig_uv = Some(uv);
                         }
                     }
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index 37678bfd880..8d1194ee539 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -277,23 +277,7 @@ where
         param_env: I::ParamEnv,
         ty: I::Ty,
     ) -> Result<I::Ty, NoSolution> {
-        if let ty::Alias(..) = ty.kind() {
-            let normalized_ty = self.next_ty_infer();
-            let alias_relate_goal = Goal::new(
-                self.cx(),
-                param_env,
-                ty::PredicateKind::AliasRelate(
-                    ty.into(),
-                    normalized_ty.into(),
-                    ty::AliasRelationDirection::Equate,
-                ),
-            );
-            self.add_goal(GoalSource::Misc, alias_relate_goal);
-            self.try_evaluate_added_goals()?;
-            Ok(self.resolve_vars_if_possible(normalized_ty))
-        } else {
-            Ok(ty)
-        }
+        self.structurally_normalize_term(param_env, ty.into()).map(|term| term.expect_ty())
     }
 
     /// Normalize a const for when it is structurally matched on, or more likely
@@ -308,22 +292,34 @@ where
         param_env: I::ParamEnv,
         ct: I::Const,
     ) -> Result<I::Const, NoSolution> {
-        if let ty::ConstKind::Unevaluated(..) = ct.kind() {
-            let normalized_ct = self.next_const_infer();
+        self.structurally_normalize_term(param_env, ct.into()).map(|term| term.expect_const())
+    }
+
+    /// Normalize a term for when it is structurally matched on.
+    ///
+    /// This function is necessary in nearly all cases before matching on a ty/const.
+    /// Not doing so is likely to be incomplete and therefore unsound during coherence.
+    fn structurally_normalize_term(
+        &mut self,
+        param_env: I::ParamEnv,
+        term: I::Term,
+    ) -> Result<I::Term, NoSolution> {
+        if let Some(_) = term.to_alias_term() {
+            let normalized_term = self.next_term_infer_of_kind(term);
             let alias_relate_goal = Goal::new(
                 self.cx(),
                 param_env,
                 ty::PredicateKind::AliasRelate(
-                    ct.into(),
-                    normalized_ct.into(),
+                    term,
+                    normalized_term,
                     ty::AliasRelationDirection::Equate,
                 ),
             );
             self.add_goal(GoalSource::Misc, alias_relate_goal);
             self.try_evaluate_added_goals()?;
-            Ok(self.resolve_vars_if_possible(normalized_ct))
+            Ok(self.resolve_vars_if_possible(normalized_term))
         } else {
-            Ok(ct)
+            Ok(term)
         }
     }
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 4faa243c02a..513fc9355c8 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -8,7 +8,6 @@ use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::solve::CanonicalResponse;
 use rustc_type_ir::visit::TypeVisitableExt as _;
 use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate};
-use smallvec::SmallVec;
 use tracing::{instrument, trace};
 
 use crate::delegate::SolverDelegate;
@@ -1199,33 +1198,42 @@ where
         // nested requirements, over all others. This is a fix for #53123 and
         // prevents where-bounds from accidentally extending the lifetime of a
         // variable.
-        if candidates
-            .iter()
-            .any(|c| matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial)))
-        {
-            let trivial_builtin_impls: SmallVec<[_; 1]> = candidates
-                .iter()
-                .filter(|c| {
-                    matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
-                })
-                .map(|c| c.result)
-                .collect();
+        let mut trivial_builtin_impls = candidates.iter().filter(|c| {
+            matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
+        });
+        if let Some(candidate) = trivial_builtin_impls.next() {
             // There should only ever be a single trivial builtin candidate
             // as they would otherwise overlap.
-            assert_eq!(trivial_builtin_impls.len(), 1);
-            return if let Some(response) = self.try_merge_responses(&trivial_builtin_impls) {
-                Ok((response, Some(TraitGoalProvenVia::Misc)))
-            } else {
-                Ok((self.bail_with_ambiguity(&trivial_builtin_impls), None))
-            };
+            assert!(trivial_builtin_impls.next().is_none());
+            return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
         }
 
         // If there are non-global where-bounds, prefer where-bounds
         // (including global ones) over everything else.
         let has_non_global_where_bounds = candidates.iter().any(|c| match c.source {
             CandidateSource::ParamEnv(idx) => {
-                let where_bound = goal.param_env.caller_bounds().get(idx);
-                where_bound.has_bound_vars() || !where_bound.is_global()
+                let where_bound = goal.param_env.caller_bounds().get(idx).unwrap();
+                let ty::ClauseKind::Trait(trait_pred) = where_bound.kind().skip_binder() else {
+                    unreachable!("expected trait-bound: {where_bound:?}");
+                };
+
+                if trait_pred.has_bound_vars() || !trait_pred.is_global() {
+                    return true;
+                }
+
+                // We don't consider a trait-bound global if it has a projection bound.
+                //
+                // See ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
+                // for an example where this is necessary.
+                for p in goal.param_env.caller_bounds().iter() {
+                    if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() {
+                        if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref {
+                            return true;
+                        }
+                    }
+                }
+
+                false
             }
             _ => false,
         });
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index f78d9dc2bfc..50287b706ce 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -3233,7 +3233,7 @@ pub(crate) struct MalformedCfgAttr {
 pub(crate) struct UnknownBuiltinConstruct {
     #[primary_span]
     pub span: Span,
-    pub name: Symbol,
+    pub name: Ident,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index f963a424a7f..e681987ff07 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -11,18 +11,21 @@
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
+#![feature(string_from_utf8_lossy_owned)]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
 
-use std::path::Path;
+use std::path::{Path, PathBuf};
+use std::str::Utf8Error;
 
 use rustc_ast as ast;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::{AttrItem, Attribute, MetaItemInner, token};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Diag, FatalError, PResult};
+use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize};
 use rustc_session::parse::ParseSess;
+use rustc_span::source_map::SourceMap;
 use rustc_span::{FileName, SourceFile, Span};
 pub use unicode_normalization::UNICODE_VERSION as UNICODE_NORMALIZATION_VERSION;
 
@@ -73,9 +76,22 @@ pub fn new_parser_from_file<'a>(
     path: &Path,
     sp: Option<Span>,
 ) -> Result<Parser<'a>, Vec<Diag<'a>>> {
-    let source_file = psess.source_map().load_file(path).unwrap_or_else(|e| {
-        let msg = format!("couldn't read {}: {}", path.display(), e);
+    let sm = psess.source_map();
+    let source_file = sm.load_file(path).unwrap_or_else(|e| {
+        let msg = format!("couldn't read `{}`: {}", path.display(), e);
         let mut err = psess.dcx().struct_fatal(msg);
+        if let Ok(contents) = std::fs::read(path)
+            && let Err(utf8err) = String::from_utf8(contents.clone())
+        {
+            utf8_error(
+                sm,
+                &path.display().to_string(),
+                sp,
+                &mut err,
+                utf8err.utf8_error(),
+                &contents,
+            );
+        }
         if let Some(sp) = sp {
             err.span(sp);
         }
@@ -84,6 +100,49 @@ pub fn new_parser_from_file<'a>(
     new_parser_from_source_file(psess, source_file)
 }
 
+pub fn utf8_error<E: EmissionGuarantee>(
+    sm: &SourceMap,
+    path: &str,
+    sp: Option<Span>,
+    err: &mut Diag<'_, E>,
+    utf8err: Utf8Error,
+    contents: &[u8],
+) {
+    // The file exists, but it wasn't valid UTF-8.
+    let start = utf8err.valid_up_to();
+    let note = format!("invalid utf-8 at byte `{start}`");
+    let msg = if let Some(len) = utf8err.error_len() {
+        format!(
+            "byte{s} `{bytes}` {are} not valid utf-8",
+            bytes = if len == 1 {
+                format!("{:?}", contents[start])
+            } else {
+                format!("{:?}", &contents[start..start + len])
+            },
+            s = pluralize!(len),
+            are = if len == 1 { "is" } else { "are" },
+        )
+    } else {
+        note.clone()
+    };
+    let contents = String::from_utf8_lossy(contents).to_string();
+    let source = sm.new_source_file(PathBuf::from(path).into(), contents);
+    let span = Span::with_root_ctxt(
+        source.normalized_byte_pos(start as u32),
+        source.normalized_byte_pos(start as u32),
+    );
+    if span.is_dummy() {
+        err.note(note);
+    } else {
+        if sp.is_some() {
+            err.span_note(span, msg);
+        } else {
+            err.span(span);
+            err.span_label(span, msg);
+        }
+    }
+}
+
 /// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing
 /// the initial token stream.
 fn new_parser_from_source_file(
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 7533e75ffe2..a5b73ce4098 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1958,7 +1958,7 @@ impl<'a> Parser<'a> {
         } else {
             let err = self.dcx().create_err(errors::UnknownBuiltinConstruct {
                 span: lo.to(ident.span),
-                name: ident.name,
+                name: ident,
             });
             return Err(err);
         };
@@ -2095,7 +2095,7 @@ impl<'a> Parser<'a> {
                     // point literal here, since there's no use of the exponent
                     // syntax that also constitutes a valid integer, so we need
                     // not check for that.
-                    if suffix.map_or(true, |s| s == sym::f32 || s == sym::f64)
+                    if suffix.is_none_or(|s| s == sym::f32 || s == sym::f64)
                         && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_')
                         && self.token.span.hi() == next_token.span.lo()
                     {
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 10756be6afb..714a60cb179 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -189,8 +189,9 @@ pub struct Parser<'a> {
 }
 
 // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with
-// nonterminals. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_pointer_width = "64", not(target_arch = "s390x")))]
+// nonterminals. Make sure it doesn't unintentionally get bigger. We only check a few arches
+// though, because `TokenTypeSet(u128)` alignment varies on others, changing the total size.
+#[cfg(all(target_pointer_width = "64", any(target_arch = "aarch64", target_arch = "x86_64")))]
 rustc_data_structures::static_assert_size!(Parser<'_>, 288);
 
 /// Stores span information about a closure.
@@ -1597,45 +1598,35 @@ impl<'a> Parser<'a> {
     // Only used when debugging.
     #[allow(unused)]
     pub(crate) fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug + '_ {
-        struct DebugParser<'dbg> {
-            parser: &'dbg Parser<'dbg>,
-            lookahead: usize,
-        }
-
-        impl fmt::Debug for DebugParser<'_> {
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                let Self { parser, lookahead } = self;
-                let mut dbg_fmt = f.debug_struct("Parser"); // or at least, one view of
-
-                // we don't need N spans, but we want at least one, so print all of prev_token
-                dbg_fmt.field("prev_token", &parser.prev_token);
-                let mut tokens = vec![];
-                for i in 0..*lookahead {
-                    let tok = parser.look_ahead(i, |tok| tok.kind.clone());
-                    let is_eof = tok == TokenKind::Eof;
-                    tokens.push(tok);
-                    if is_eof {
-                        // Don't look ahead past EOF.
-                        break;
-                    }
-                }
-                dbg_fmt.field_with("tokens", |field| field.debug_list().entries(tokens).finish());
-                dbg_fmt.field("approx_token_stream_pos", &parser.num_bump_calls);
-
-                // some fields are interesting for certain values, as they relate to macro parsing
-                if let Some(subparser) = parser.subparser_name {
-                    dbg_fmt.field("subparser_name", &subparser);
-                }
-                if let Recovery::Forbidden = parser.recovery {
-                    dbg_fmt.field("recovery", &parser.recovery);
+        fmt::from_fn(move |f| {
+            let mut dbg_fmt = f.debug_struct("Parser"); // or at least, one view of
+
+            // we don't need N spans, but we want at least one, so print all of prev_token
+            dbg_fmt.field("prev_token", &self.prev_token);
+            let mut tokens = vec![];
+            for i in 0..lookahead {
+                let tok = self.look_ahead(i, |tok| tok.kind.clone());
+                let is_eof = tok == TokenKind::Eof;
+                tokens.push(tok);
+                if is_eof {
+                    // Don't look ahead past EOF.
+                    break;
                 }
+            }
+            dbg_fmt.field_with("tokens", |field| field.debug_list().entries(tokens).finish());
+            dbg_fmt.field("approx_token_stream_pos", &self.num_bump_calls);
 
-                // imply there's "more to know" than this view
-                dbg_fmt.finish_non_exhaustive()
+            // some fields are interesting for certain values, as they relate to macro parsing
+            if let Some(subparser) = self.subparser_name {
+                dbg_fmt.field("subparser_name", &subparser);
+            }
+            if let Recovery::Forbidden = self.recovery {
+                dbg_fmt.field("recovery", &self.recovery);
             }
-        }
 
-        DebugParser { parser: self, lookahead }
+            // imply there's "more to know" than this view
+            dbg_fmt.finish_non_exhaustive()
+        })
     }
 
     pub fn clear_expected_token_types(&mut self) {
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 8b6b37c0f8f..86f673c100c 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -11,7 +11,7 @@ use rustc_session::errors::report_lit_error;
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE};
 use rustc_session::parse::ParseSess;
-use rustc_span::{BytePos, Span, Symbol, sym};
+use rustc_span::{Span, Symbol, sym};
 
 use crate::{errors, parse_in};
 
@@ -164,11 +164,7 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr:
             // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the
             // `unsafe(`, `)` right after and right before the opening and closing
             // square bracket respectively.
-            let diag_span = if attr_item.span().can_be_used_for_suggestions() {
-                attr_item.span()
-            } else {
-                attr.span.with_lo(attr.span.lo() + BytePos(2)).with_hi(attr.span.hi() - BytePos(1))
-            };
+            let diag_span = attr_item.span();
 
             if attr.span.at_least_rust_2024() {
                 psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 9eb335cb34c..5418f054beb 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -514,13 +514,7 @@ impl<'a> Parser<'a> {
 
     /// Consumes all whitespace characters until the first non-whitespace character
     fn ws(&mut self) {
-        while let Some(&(_, c)) = self.cur.peek() {
-            if c.is_whitespace() {
-                self.cur.next();
-            } else {
-                break;
-            }
-        }
+        while let Some(_) = self.cur.next_if(|&(_, c)| c.is_whitespace()) {}
     }
 
     /// Parses all of a string which is to be considered a "raw literal" in a
@@ -545,7 +539,7 @@ impl<'a> Parser<'a> {
                 }
             }
         }
-        &self.input[start..self.input.len()]
+        &self.input[start..]
     }
 
     /// Parses an `Argument` structure, or what's contained within braces inside the format string.
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 3ed600a717f..978cb7af242 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -502,11 +502,6 @@ passes_multiple_rustc_main =
     .first = first `#[rustc_main]` function
     .additional = additional `#[rustc_main]` function
 
-passes_multiple_start_functions =
-    multiple `start` functions
-    .label = multiple `start` functions
-    .previous = previous `#[start]` function here
-
 passes_must_not_suspend =
     `must_not_suspend` attribute should be applied to a struct, enum, union, or trait
     .label = is not a struct, enum, union, or trait
@@ -817,6 +812,9 @@ passes_unused_duplicate =
 passes_unused_empty_lints_note =
     attribute `{$name}` with an empty list has no effect
 
+passes_unused_linker_warnings_note =
+    the `linker_warnings` lint can only be controlled at the root of a crate that needs to be linked
+
 passes_unused_multiple =
     multiple `{$name}` attributes
     .suggestion = remove this attribute
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 1b2b8ac5dd9..e19819a22b4 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -25,6 +25,7 @@ use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
+use rustc_session::config::CrateType;
 use rustc_session::lint::builtin::{
     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
     UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
@@ -275,7 +276,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     | sym::lang
                     | sym::needs_allocator
                     | sym::default_lib_allocator
-                    | sym::start
                     | sym::custom_mir,
                     ..
                 ] => {}
@@ -2328,6 +2328,42 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             && item.path == sym::reason
         {
             errors::UnusedNote::NoLints { name: attr.name_or_empty() }
+        } else if matches!(
+            attr.name_or_empty(),
+            sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
+        ) && let Some(meta) = attr.meta_item_list()
+            && meta.iter().any(|meta| {
+                meta.meta_item().map_or(false, |item| item.path == sym::linker_messages)
+            })
+        {
+            if hir_id != CRATE_HIR_ID {
+                match attr.style {
+                    ast::AttrStyle::Outer => self.tcx.emit_node_span_lint(
+                        UNUSED_ATTRIBUTES,
+                        hir_id,
+                        attr.span,
+                        errors::OuterCrateLevelAttr,
+                    ),
+                    ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
+                        UNUSED_ATTRIBUTES,
+                        hir_id,
+                        attr.span,
+                        errors::InnerCrateLevelAttr,
+                    ),
+                };
+                return;
+            } else {
+                let never_needs_link = self
+                    .tcx
+                    .crate_types()
+                    .iter()
+                    .all(|kind| matches!(kind, CrateType::Rlib | CrateType::Staticlib));
+                if never_needs_link {
+                    errors::UnusedNote::LinkerWarningsBinaryCrateOnly
+                } else {
+                    return;
+                }
+            }
         } else if attr.name_or_empty() == sym::default_method_body_is_const {
             errors::UnusedNote::DefaultMethodBodyConst
         } else {
@@ -2655,7 +2691,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
         sym::repr,
         sym::path,
         sym::automatically_derived,
-        sym::start,
         sym::rustc_main,
         sym::derive,
         sym::test,
@@ -2810,7 +2845,7 @@ fn doc_fake_variadic_is_allowed_self_ty(self_ty: &hir::Ty<'_>) -> bool {
             && let Some(&[hir::GenericArg::Type(ty)]) =
                 path.segments.last().map(|last| last.args().args)
         {
-            doc_fake_variadic_is_allowed_self_ty(ty)
+            doc_fake_variadic_is_allowed_self_ty(ty.as_unambig_ty())
         } else {
             false
         })
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index c5dc8e68fe8..e5b63b9b4a6 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -460,7 +460,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                             }
 
                             // mark self_ty live
-                            intravisit::walk_ty(self, impl_ref.self_ty);
+                            intravisit::walk_unambig_ty(self, impl_ref.self_ty);
                             if let Some(&impl_item_id) =
                                 self.tcx.impl_item_implementor_ids(impl_id).get(&trait_item_id)
                             {
@@ -1231,7 +1231,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
                     continue;
                 }
 
-                let is_positional = variant.fields.raw.first().map_or(false, |field| {
+                let is_positional = variant.fields.raw.first().is_some_and(|field| {
                     field.name.as_str().starts_with(|c: char| c.is_ascii_digit())
                 });
                 let report_on =
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 4949a4316a7..22291c9282d 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -10,9 +10,7 @@ use rustc_session::RemapFileNameExt;
 use rustc_session::config::{CrateType, EntryFnType, RemapPathScopeComponents, sigpipe};
 use rustc_span::{Span, Symbol, sym};
 
-use crate::errors::{
-    AttrOnlyInFunctions, ExternMain, MultipleRustcMain, MultipleStartFunctions, NoMainErr,
-};
+use crate::errors::{AttrOnlyInFunctions, ExternMain, MultipleRustcMain, NoMainErr};
 
 struct EntryContext<'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -20,9 +18,6 @@ struct EntryContext<'tcx> {
     /// The function has the `#[rustc_main]` attribute.
     rustc_main_fn: Option<(LocalDefId, Span)>,
 
-    /// The function that has the attribute `#[start]` on it.
-    start_fn: Option<(LocalDefId, Span)>,
-
     /// The functions that one might think are `main` but aren't, e.g.
     /// main functions not defined at the top level. For diagnostics.
     non_main_fns: Vec<Span>,
@@ -40,8 +35,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
         return None;
     }
 
-    let mut ctxt =
-        EntryContext { tcx, rustc_main_fn: None, start_fn: None, non_main_fns: Vec::new() };
+    let mut ctxt = EntryContext { tcx, rustc_main_fn: None, non_main_fns: Vec::new() };
 
     for id in tcx.hir().items() {
         check_and_search_item(id, &mut ctxt);
@@ -57,7 +51,7 @@ fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Opti
 
 fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
     if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) {
-        for attr in [sym::start, sym::rustc_main] {
+        for attr in [sym::rustc_main] {
             if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
                 ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr });
             }
@@ -91,24 +85,11 @@ fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
                 });
             }
         }
-        EntryPointType::Start => {
-            if ctxt.start_fn.is_none() {
-                ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
-            } else {
-                ctxt.tcx.dcx().emit_err(MultipleStartFunctions {
-                    span: ctxt.tcx.def_span(id.owner_id),
-                    labeled: ctxt.tcx.def_span(id.owner_id.to_def_id()),
-                    previous: ctxt.start_fn.unwrap().1,
-                });
-            }
-        }
     }
 }
 
 fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
-    if let Some((def_id, _)) = visitor.start_fn {
-        Some((def_id.to_def_id(), EntryFnType::Start))
-    } else if let Some((local_def_id, _)) = visitor.rustc_main_fn {
+    if let Some((local_def_id, _)) = visitor.rustc_main_fn {
         let def_id = local_def_id.to_def_id();
         Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) }))
     } else {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index c3043ac60aa..0aa50ad19ff 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -802,6 +802,8 @@ pub(crate) enum UnusedNote {
     NoLints { name: Symbol },
     #[note(passes_unused_default_method_body_const_note)]
     DefaultMethodBodyConst,
+    #[note(passes_unused_linker_warnings_note)]
+    LinkerWarningsBinaryCrateOnly,
 }
 
 #[derive(LintDiagnostic)]
@@ -1314,17 +1316,6 @@ pub(crate) struct MultipleRustcMain {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_multiple_start_functions, code = E0138)]
-pub(crate) struct MultipleStartFunctions {
-    #[primary_span]
-    pub span: Span,
-    #[label]
-    pub labeled: Span,
-    #[label(passes_previous)]
-    pub previous: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_extern_main)]
 pub(crate) struct ExternMain {
     #[primary_span]
@@ -1800,7 +1791,7 @@ pub(crate) struct UnusedAssign {
 pub(crate) struct UnusedAssignSuggestion {
     pub pre: &'static str,
     #[suggestion_part(code = "{pre}mut ")]
-    pub ty_span: Span,
+    pub ty_span: Option<Span>,
     #[suggestion_part(code = "")]
     pub ty_ref_span: Span,
     #[suggestion_part(code = "*")]
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 6617cf2f723..8b10543f6fd 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -5,8 +5,7 @@
 use rustc_ast::visit::BoundKind;
 use rustc_ast::{self as ast, NodeId, visit as ast_visit};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir as hir;
-use rustc_hir::{HirId, intravisit as hir_visit};
+use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::util::common::to_readable_str;
@@ -363,7 +362,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         hir_visit::walk_expr_field(self, f)
     }
 
-    fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
+    fn visit_ty(&mut self, t: &'v hir::Ty<'v, AmbigArg>) {
         record_variants!((self, t, t.kind, Some(t.hir_id), hir, Ty, TyKind), [
             InferDelegation,
             Slice,
@@ -476,7 +475,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
             hir::GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
             hir::GenericArg::Type(ty) => self.visit_ty(ty),
             hir::GenericArg::Const(ct) => self.visit_const_arg(ct),
-            hir::GenericArg::Infer(inf) => self.visit_infer(inf),
+            hir::GenericArg::Infer(inf) => self.visit_id(inf.hir_id),
         }
     }
 
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 426899a4d5c..73da8855e10 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -1620,24 +1620,28 @@ impl<'tcx> Liveness<'_, 'tcx> {
             && let item = self.ir.tcx.hir_owner_node(item_id)
             && let Some(fn_decl) = item.fn_decl()
             && let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = pat.kind
-            && let Some((ty_span, pre)) = fn_decl
+            && let Some((lt, mut_ty)) = fn_decl
                 .inputs
                 .iter()
                 .filter_map(|ty| {
                     if ty.span == *ty_span
                         && let hir::TyKind::Ref(lt, mut_ty) = ty.kind
                     {
-                        // `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
-                        Some((
-                            mut_ty.ty.span.shrink_to_lo(),
-                            if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " },
-                        ))
+                        Some((lt, mut_ty))
                     } else {
                         None
                     }
                 })
                 .next()
         {
+            let ty_span = if mut_ty.mutbl.is_mut() {
+                // Leave `&'name mut Ty` and `&mut Ty` as they are (#136028).
+                None
+            } else {
+                // `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
+                Some(mut_ty.ty.span.shrink_to_lo())
+            };
+            let pre = if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " };
             Some(errors::UnusedAssignSuggestion {
                 ty_span,
                 pre,
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 60734122e63..a52f080038d 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -11,12 +11,11 @@ use rustc_attr_parsing::{
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
 use rustc_feature::{ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature};
-use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId};
 use rustc_hir::hir_id::CRATE_HIR_ID;
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
+use rustc_hir::intravisit::{self, Visitor, VisitorExt};
+use rustc_hir::{self as hir, AmbigArg, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
 use rustc_middle::middle::privacy::EffectiveVisibilities;
@@ -802,7 +801,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                     )) = stab
                     {
                         let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
-                        c.visit_ty(self_ty);
+                        c.visit_ty_unambig(self_ty);
                         c.visit_trait_ref(t);
 
                         // do not lint when the trait isn't resolved, since resolution error should
@@ -1028,7 +1027,7 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
         intravisit::walk_trait_ref(self, t)
     }
 
-    fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
+    fn visit_ty(&mut self, t: &'tcx Ty<'tcx, AmbigArg>) {
         if let TyKind::Never = t.kind {
             self.fully_stable = false;
         }
@@ -1042,12 +1041,12 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
 
     fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
         for ty in fd.inputs {
-            self.visit_ty(ty)
+            self.visit_ty_unambig(ty)
         }
         if let hir::FnRetTy::Return(output_ty) = fd.output {
             match output_ty.kind {
                 TyKind::Never => {} // `-> !` is stable
-                _ => self.visit_ty(output_ty),
+                _ => self.visit_ty_unambig(output_ty),
             }
         }
     }
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index ae991e3ce40..2694cf472f4 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -794,9 +794,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                 // fictitious values after `{u,i}size::MAX` (see [`IntRange::split`] for why we do
                 // this). We show this to the user as `usize::MAX..` which is slightly incorrect but
                 // probably clear enough.
-                let c = ty.numeric_max_val(cx.tcx).unwrap();
-                let value = mir::Const::from_ty_const(c, ty.0, cx.tcx);
-                lo = PatRangeBoundary::Finite(value);
+                lo = PatRangeBoundary::Finite(ty.numeric_max_val(cx.tcx).unwrap());
             }
             let hi = if let Some(hi) = range.hi.minus_one() {
                 hi
diff --git a/compiler/rustc_privacy/messages.ftl b/compiler/rustc_privacy/messages.ftl
index 7785f1a7f81..43c34a109d7 100644
--- a/compiler/rustc_privacy/messages.ftl
+++ b/compiler/rustc_privacy/messages.ftl
@@ -1,5 +1,19 @@
-privacy_field_is_private = field `{$field_name}` of {$variant_descr} `{$def_path_str}` is private
-privacy_field_is_private_is_update_syntax_label = field `{$field_name}` is private
+privacy_field_is_private =
+    {$len ->
+        [1] field
+        *[other] fields
+    } {$field_names} of {$variant_descr} `{$def_path_str}` {$len ->
+        [1] is
+        *[other] are
+    } private
+    .label = in this type
+privacy_field_is_private_is_update_syntax_label = {$rest_len ->
+        [1] field
+        *[other] fields
+    } {$rest_field_names} {$rest_len ->
+        [1] is
+        *[other] are
+    } private
 privacy_field_is_private_label = private field
 
 privacy_from_private_dep_in_public_interface =
diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs
index f5e641eb642..4d1d58c0852 100644
--- a/compiler/rustc_privacy/src/errors.rs
+++ b/compiler/rustc_privacy/src/errors.rs
@@ -1,5 +1,5 @@
-use rustc_errors::DiagArgFromDisplay;
 use rustc_errors::codes::*;
+use rustc_errors::{DiagArgFromDisplay, MultiSpan};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
@@ -7,12 +7,15 @@ use rustc_span::{Span, Symbol};
 #[diag(privacy_field_is_private, code = E0451)]
 pub(crate) struct FieldIsPrivate {
     #[primary_span]
-    pub span: Span,
-    pub field_name: Symbol,
+    pub span: MultiSpan,
+    #[label]
+    pub struct_span: Option<Span>,
+    pub field_names: String,
     pub variant_descr: &'static str,
     pub def_path_str: String,
     #[subdiagnostic]
-    pub label: FieldIsPrivateLabel,
+    pub labels: Vec<FieldIsPrivateLabel>,
+    pub len: usize,
 }
 
 #[derive(Subdiagnostic)]
@@ -21,7 +24,8 @@ pub(crate) enum FieldIsPrivateLabel {
     IsUpdateSyntax {
         #[primary_span]
         span: Span,
-        field_name: Symbol,
+        rest_field_names: String,
+        rest_len: usize,
     },
     #[label(privacy_field_is_private_label)]
     Other {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index e484cfed06b..d19df08519d 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -24,10 +24,11 @@ use rustc_ast::MacroDef;
 use rustc_ast::visit::{VisitorResult, try_visit};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
+use rustc_errors::MultiSpan;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId};
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind};
+use rustc_hir::intravisit::{self, InferKind, Visitor};
+use rustc_hir::{AmbigArg, AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind};
 use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
@@ -38,7 +39,7 @@ use rustc_middle::ty::{
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
-use rustc_span::{Ident, Span, kw, sym};
+use rustc_span::{Ident, Span, Symbol, kw, sym};
 use tracing::debug;
 use {rustc_attr_parsing as attr, rustc_hir as hir};
 
@@ -921,31 +922,95 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
         &mut self,
         hir_id: hir::HirId,    // ID of the field use
         use_ctxt: Span,        // syntax context of the field name at the use site
-        span: Span,            // span of the field pattern, e.g., `x: 0`
         def: ty::AdtDef<'tcx>, // definition of the struct or enum
         field: &'tcx ty::FieldDef,
-        in_update_syntax: bool,
-    ) {
+    ) -> bool {
         if def.is_enum() {
-            return;
+            return true;
         }
 
         // definition of the field
         let ident = Ident::new(kw::Empty, use_ctxt);
         let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1;
-        if !field.vis.is_accessible_from(def_id, self.tcx) {
-            self.tcx.dcx().emit_err(FieldIsPrivate {
-                span,
-                field_name: field.name,
-                variant_descr: def.variant_descr(),
-                def_path_str: self.tcx.def_path_str(def.did()),
-                label: if in_update_syntax {
-                    FieldIsPrivateLabel::IsUpdateSyntax { span, field_name: field.name }
-                } else {
-                    FieldIsPrivateLabel::Other { span }
-                },
-            });
+        !field.vis.is_accessible_from(def_id, self.tcx)
+    }
+
+    // Checks that a field in a struct constructor (expression or pattern) is accessible.
+    fn emit_unreachable_field_error(
+        &mut self,
+        fields: Vec<(Symbol, Span, bool /* field is present */)>,
+        def: ty::AdtDef<'tcx>, // definition of the struct or enum
+        update_syntax: Option<Span>,
+        struct_span: Span,
+    ) {
+        if def.is_enum() || fields.is_empty() {
+            return;
         }
+
+        //   error[E0451]: fields `beta` and `gamma` of struct `Alpha` are private
+        //   --> $DIR/visibility.rs:18:13
+        //    |
+        // LL |     let _x = Alpha {
+        //    |              ----- in this type      # from `def`
+        // LL |         beta: 0,
+        //    |         ^^^^^^^ private field        # `fields.2` is `true`
+        // LL |         ..
+        //    |         ^^ field `gamma` is private  # `fields.2` is `false`
+
+        // Get the list of all private fields for the main message.
+        let field_names: Vec<_> = fields.iter().map(|(name, _, _)| name).collect();
+        let field_names = match &field_names[..] {
+            [] => return,
+            [name] => format!("`{name}`"),
+            [fields @ .., last] => format!(
+                "{} and `{last}`",
+                fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "),
+            ),
+        };
+        let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::<Vec<Span>>().into();
+
+        // Get the list of all private fields when pointing at the `..rest`.
+        let rest_field_names: Vec<_> =
+            fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect();
+        let rest_len = rest_field_names.len();
+        let rest_field_names = match &rest_field_names[..] {
+            [] => String::new(),
+            [name] => format!("`{name}`"),
+            [fields @ .., last] => format!(
+                "{} and `{last}`",
+                fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "),
+            ),
+        };
+        // Get all the labels for each field or `..rest` in the primary MultiSpan.
+        let labels = fields
+            .iter()
+            .filter(|(_, _, is_present)| *is_present)
+            .map(|(_, span, _)| FieldIsPrivateLabel::Other { span: *span })
+            .chain(update_syntax.iter().map(|span| FieldIsPrivateLabel::IsUpdateSyntax {
+                span: *span,
+                rest_field_names: rest_field_names.clone(),
+                rest_len,
+            }))
+            .collect();
+
+        self.tcx.dcx().emit_err(FieldIsPrivate {
+            span,
+            struct_span: if self
+                .tcx
+                .sess
+                .source_map()
+                .is_multiline(fields[0].1.between(struct_span))
+            {
+                Some(struct_span)
+            } else {
+                None
+            },
+            field_names: field_names.clone(),
+            variant_descr: def.variant_descr(),
+            def_path_str: self.tcx.def_path_str(def.did()),
+            labels,
+            len: fields.len(),
+        });
     }
 
     fn check_expanded_fields(
@@ -955,7 +1020,9 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
         fields: &[hir::ExprField<'tcx>],
         hir_id: hir::HirId,
         span: Span,
+        struct_span: Span,
     ) {
+        let mut failed_fields = vec![];
         for (vf_index, variant_field) in variant.fields.iter_enumerated() {
             let field =
                 fields.iter().find(|f| self.typeck_results().field_index(f.hir_id) == vf_index);
@@ -963,8 +1030,15 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
                 Some(field) => (field.hir_id, field.ident.span, field.span),
                 None => (hir_id, span, span),
             };
-            self.check_field(hir_id, use_ctxt, span, adt, variant_field, true);
+            if self.check_field(hir_id, use_ctxt, adt, variant_field) {
+                let name = match field {
+                    Some(field) => field.ident.name,
+                    None => variant_field.name,
+                };
+                failed_fields.push((name, span, field.is_some()));
+            }
         }
+        self.emit_unreachable_field_error(failed_fields, adt, Some(span), struct_span);
     }
 }
 
@@ -990,24 +1064,35 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
                     // If the expression uses FRU we need to make sure all the unmentioned fields
                     // are checked for privacy (RFC 736). Rather than computing the set of
                     // unmentioned fields, just check them all.
-                    self.check_expanded_fields(adt, variant, fields, base.hir_id, base.span);
+                    self.check_expanded_fields(
+                        adt,
+                        variant,
+                        fields,
+                        base.hir_id,
+                        base.span,
+                        qpath.span(),
+                    );
                 }
                 hir::StructTailExpr::DefaultFields(span) => {
-                    self.check_expanded_fields(adt, variant, fields, expr.hir_id, span);
+                    self.check_expanded_fields(
+                        adt,
+                        variant,
+                        fields,
+                        expr.hir_id,
+                        span,
+                        qpath.span(),
+                    );
                 }
                 hir::StructTailExpr::None => {
+                    let mut failed_fields = vec![];
                     for field in fields {
-                        let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span);
+                        let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
                         let index = self.typeck_results().field_index(field.hir_id);
-                        self.check_field(
-                            hir_id,
-                            use_ctxt,
-                            span,
-                            adt,
-                            &variant.fields[index],
-                            false,
-                        );
+                        if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
+                            failed_fields.push((field.ident.name, field.ident.span, true));
+                        }
                     }
+                    self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
                 }
             }
         }
@@ -1020,11 +1105,15 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
             let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
             let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap();
             let variant = adt.variant_of_res(res);
+            let mut failed_fields = vec![];
             for field in fields {
-                let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span);
+                let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
                 let index = self.typeck_results().field_index(field.hir_id);
-                self.check_field(hir_id, use_ctxt, span, adt, &variant.fields[index], false);
+                if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
+                    failed_fields.push((field.ident.name, field.ident.span, true));
+                }
             }
+            self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
         }
 
         intravisit::walk_pat(self, pat);
@@ -1090,7 +1179,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
         self.maybe_typeck_results = old_maybe_typeck_results;
     }
 
-    fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
+    fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
         self.span = hir_ty.span;
         if self
             .visit(
@@ -1106,12 +1195,17 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
         intravisit::walk_ty(self, hir_ty);
     }
 
-    fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
-        self.span = inf.span;
+    fn visit_infer(
+        &mut self,
+        inf_id: rustc_hir::HirId,
+        inf_span: Span,
+        _kind: InferKind<'tcx>,
+    ) -> Self::Result {
+        self.span = inf_span;
         if let Some(ty) = self
             .maybe_typeck_results
-            .unwrap_or_else(|| span_bug!(inf.span, "`hir::InferArg` outside of a body"))
-            .node_type_opt(inf.hir_id)
+            .unwrap_or_else(|| span_bug!(inf_span, "Inference variable outside of a body"))
+            .node_type_opt(inf_id)
         {
             if self.visit(ty).is_break() {
                 return;
@@ -1119,7 +1213,8 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
         } else {
             // FIXME: check types of const infers here.
         }
-        intravisit::walk_inf(self, inf);
+
+        self.visit_id(inf_id)
     }
 
     // Check types of expressions
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 3e179c61f39..a8c2aa98cd0 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -567,7 +567,7 @@ pub fn print_query_stack<Qcx: QueryContext>(
     qcx: Qcx,
     mut current_query: Option<QueryJobId>,
     dcx: DiagCtxtHandle<'_>,
-    num_frames: Option<usize>,
+    limit_frames: Option<usize>,
     mut file: Option<std::fs::File>,
 ) -> usize {
     // Be careful relying on global state here: this code is called from
@@ -584,7 +584,7 @@ pub fn print_query_stack<Qcx: QueryContext>(
         let Some(query_info) = query_map.get(&query) else {
             break;
         };
-        if Some(count_printed) < num_frames || num_frames.is_none() {
+        if Some(count_printed) < limit_frames || limit_frames.is_none() {
             // Only print to stderr as many stack frames as `num_frames` when present.
             // FIXME: needs translation
             #[allow(rustc::diagnostic_outside_of_impl)]
@@ -615,5 +615,5 @@ pub fn print_query_stack<Qcx: QueryContext>(
     if let Some(ref mut file) = file {
         let _ = writeln!(file, "end of query stack");
     }
-    count_printed
+    count_total
 }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 3fe1eed243f..eec9e9a8515 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -645,10 +645,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 let self_spans = items
                     .iter()
                     .filter_map(|(use_tree, _)| {
-                        if let ast::UseTreeKind::Simple(..) = use_tree.kind {
-                            if use_tree.ident().name == kw::SelfLower {
-                                return Some(use_tree.span);
-                            }
+                        if let ast::UseTreeKind::Simple(..) = use_tree.kind
+                            && use_tree.ident().name == kw::SelfLower
+                        {
+                            return Some(use_tree.span);
                         }
 
                         None
@@ -947,19 +947,19 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         let imported_binding = self.r.import(binding, import);
         if parent == self.r.graph_root {
             let ident = ident.normalize_to_macros_2_0();
-            if let Some(entry) = self.r.extern_prelude.get(&ident) {
-                if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() {
-                    self.r.dcx().emit_err(
-                        errors::MacroExpandedExternCrateCannotShadowExternArguments {
-                            span: item.span,
-                        },
-                    );
-                    // `return` is intended to discard this binding because it's an
-                    // unregistered ambiguity error which would result in a panic
-                    // caused by inconsistency `path_res`
-                    // more details: https://github.com/rust-lang/rust/pull/111761
-                    return;
-                }
+            if let Some(entry) = self.r.extern_prelude.get(&ident)
+                && expansion != LocalExpnId::ROOT
+                && orig_name.is_some()
+                && !entry.is_import()
+            {
+                self.r.dcx().emit_err(
+                    errors::MacroExpandedExternCrateCannotShadowExternArguments { span: item.span },
+                );
+                // `return` is intended to discard this binding because it's an
+                // unregistered ambiguity error which would result in a panic
+                // caused by inconsistency `path_res`
+                // more details: https://github.com/rust-lang/rust/pull/111761
+                return;
             }
             let entry = self
                 .r
@@ -1040,10 +1040,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                         span: item.span,
                     });
                 }
-                if let ItemKind::ExternCrate(Some(orig_name)) = item.kind {
-                    if orig_name == kw::SelfLower {
-                        self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span });
-                    }
+                if let ItemKind::ExternCrate(Some(orig_name)) = item.kind
+                    && orig_name == kw::SelfLower
+                {
+                    self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span });
                 }
                 let ill_formed = |span| {
                     self.r.dcx().emit_err(errors::BadMacroImport { span });
@@ -1179,14 +1179,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             return Some((MacroKind::Bang, item.ident, item.span));
         } else if ast::attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
             return Some((MacroKind::Attr, item.ident, item.span));
-        } else if let Some(attr) = ast::attr::find_by_name(&item.attrs, sym::proc_macro_derive) {
-            if let Some(meta_item_inner) =
+        } else if let Some(attr) = ast::attr::find_by_name(&item.attrs, sym::proc_macro_derive)
+            && let Some(meta_item_inner) =
                 attr.meta_item_list().and_then(|list| list.get(0).cloned())
-            {
-                if let Some(ident) = meta_item_inner.ident() {
-                    return Some((MacroKind::Derive, ident, ident.span));
-                }
-            }
+            && let Some(ident) = meta_item_inner.ident()
+        {
+            return Some((MacroKind::Derive, ident, ident.span));
         }
         None
     }
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 5a605df88c2..1c1e8494ffc 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -397,7 +397,7 @@ impl Resolver<'_, '_> {
                 }
                 ImportKind::ExternCrate { id, .. } => {
                     let def_id = self.local_def_id(id);
-                    if self.extern_crate_map.get(&def_id).map_or(true, |&cnum| {
+                    if self.extern_crate_map.get(&def_id).is_none_or(|&cnum| {
                         !tcx.is_compiler_builtins(cnum)
                             && !tcx.is_panic_runtime(cnum)
                             && !tcx.has_global_allocator(cnum)
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index dc26d4de57a..8dc752c2cb3 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -24,13 +24,14 @@ use rustc_session::lint::builtin::{
     MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
 };
 use rustc_session::lint::{AmbiguityErrorDiag, BuiltinLintDiag};
+use rustc_session::utils::was_invoked_from_cargo;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym};
 use thin_vec::{ThinVec, thin_vec};
-use tracing::debug;
+use tracing::{debug, instrument};
 
 use crate::errors::{
     self, AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
@@ -225,10 +226,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         let (name, span) =
             (ident.name, self.tcx.sess.source_map().guess_head_span(new_binding.span));
 
-        if let Some(s) = self.name_already_seen.get(&name) {
-            if s == &span {
-                return;
-            }
+        if self.name_already_seen.get(&name) == Some(&span) {
+            return;
         }
 
         let old_kind = match (ns, old_binding.module()) {
@@ -322,7 +321,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id();
         let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
         let from_item =
-            self.extern_prelude.get(&ident).map_or(true, |entry| entry.introduced_by_item);
+            self.extern_prelude.get(&ident).is_none_or(|entry| entry.introduced_by_item);
         // Only suggest removing an import if both bindings are to the same def, if both spans
         // aren't dummy spans. Further, if both bindings are imports, then the ident must have
         // been introduced by an item.
@@ -380,20 +379,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 suggestion = Some(format!("self as {suggested_name}"))
             }
             ImportKind::Single { source, .. } => {
-                if let Some(pos) =
-                    source.span.hi().0.checked_sub(binding_span.lo().0).map(|pos| pos as usize)
+                if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0)
+                    && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span)
+                    && pos as usize <= snippet.len()
                 {
-                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span) {
-                        if pos <= snippet.len() {
-                            span = binding_span
-                                .with_lo(binding_span.lo() + BytePos(pos as u32))
-                                .with_hi(
-                                    binding_span.hi()
-                                        - BytePos(if snippet.ends_with(';') { 1 } else { 0 }),
-                                );
-                            suggestion = Some(format!(" as {suggested_name}"));
-                        }
-                    }
+                    span = binding_span.with_lo(binding_span.lo() + BytePos(pos)).with_hi(
+                        binding_span.hi() - BytePos(if snippet.ends_with(';') { 1 } else { 0 }),
+                    );
+                    suggestion = Some(format!(" as {suggested_name}"));
                 }
             }
             ImportKind::ExternCrate { source, target, .. } => {
@@ -510,13 +503,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // If the first element of our path was actually resolved to an
         // `ExternCrate` (also used for `crate::...`) then no need to issue a
         // warning, this looks all good!
-        if let Some(binding) = second_binding {
-            if let NameBindingKind::Import { import, .. } = binding.kind {
-                // Careful: we still want to rewrite paths from renamed extern crates.
-                if let ImportKind::ExternCrate { source: None, .. } = import.kind {
-                    return;
-                }
-            }
+        if let Some(binding) = second_binding
+            && let NameBindingKind::Import { import, .. } = binding.kind
+            // Careful: we still want to rewrite paths from renamed extern crates.
+            && let ImportKind::ExternCrate { source: None, .. } = import.kind
+        {
+            return;
         }
 
         let diag = BuiltinLintDiag::AbsPathWithModule(root_span);
@@ -537,7 +529,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     ) {
         module.for_each_child(self, |_this, ident, _ns, binding| {
             let res = binding.res();
-            if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == ident.span.ctxt()) {
+            if filter_fn(res) && ctxt.is_none_or(|ctxt| ctxt == ident.span.ctxt()) {
                 names.push(TypoSuggestion::typo_from_ident(ident, res));
             }
         });
@@ -685,7 +677,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 }
                 if could_be_path {
                     let import_suggestions = self.lookup_import_candidates(
-                        Ident::with_dummy_span(name),
+                        name,
                         Namespace::ValueNS,
                         &parent_scope,
                         &|res: Res| {
@@ -809,7 +801,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     }
                     err.multipart_suggestion(msg, suggestions, applicability);
                 }
-
                 if let Some(ModuleOrUniformRoot::Module(module)) = module
                     && let Some(module) = module.opt_def_id()
                     && let Some(segment) = segment
@@ -1047,20 +1038,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     if filter_fn(res) {
                         for derive in parent_scope.derives {
                             let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
-                            if let Ok((Some(ext), _)) = this.resolve_macro_path(
+                            let Ok((Some(ext), _)) = this.resolve_macro_path(
                                 derive,
                                 Some(MacroKind::Derive),
                                 parent_scope,
                                 false,
                                 false,
                                 None,
-                            ) {
-                                suggestions.extend(
-                                    ext.helper_attrs
-                                        .iter()
-                                        .map(|name| TypoSuggestion::typo_from_name(*name, res)),
-                                );
-                            }
+                            ) else {
+                                continue;
+                            };
+                            suggestions.extend(
+                                ext.helper_attrs
+                                    .iter()
+                                    .map(|name| TypoSuggestion::typo_from_name(*name, res)),
+                            );
                         }
                     }
                 }
@@ -1215,12 +1207,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 }
 
                 // #90113: Do not count an inaccessible reexported item as a candidate.
-                if let NameBindingKind::Import { binding, .. } = name_binding.kind {
-                    if this.is_accessible_from(binding.vis, parent_scope.module)
-                        && !this.is_accessible_from(name_binding.vis, parent_scope.module)
-                    {
-                        return;
-                    }
+                if let NameBindingKind::Import { binding, .. } = name_binding.kind
+                    && this.is_accessible_from(binding.vis, parent_scope.module)
+                    && !this.is_accessible_from(name_binding.vis, parent_scope.module)
+                {
+                    return;
                 }
 
                 let res = name_binding.res();
@@ -1229,7 +1220,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     _ => res.opt_def_id(),
                 };
                 let child_doc_visible = doc_visible
-                    && (did.map_or(true, |did| did.is_local() || !this.tcx.is_doc_hidden(did)));
+                    && did.is_none_or(|did| did.is_local() || !this.tcx.is_doc_hidden(did));
 
                 // collect results based on the filter function
                 // avoid suggesting anything from the same module in which we are resolving
@@ -1253,14 +1244,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     segms.push(ast::PathSegment::from_ident(ident));
                     let path = Path { span: name_binding.span, segments: segms, tokens: None };
 
-                    if child_accessible {
+                    if child_accessible
                         // Remove invisible match if exists
-                        if let Some(idx) = candidates
+                        && let Some(idx) = candidates
                             .iter()
                             .position(|v: &ImportSuggestion| v.did == did && !v.accessible)
-                        {
-                            candidates.remove(idx);
-                        }
+                    {
+                        candidates.remove(idx);
                     }
 
                     if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
@@ -1373,48 +1363,50 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     // otherwise cause duplicate suggestions.
                     continue;
                 }
-                let crate_id = self.crate_loader(|c| c.maybe_process_path_extern(ident.name));
-                if let Some(crate_id) = crate_id {
-                    let crate_def_id = crate_id.as_def_id();
-                    let crate_root = self.expect_module(crate_def_id);
-
-                    // Check if there's already an item in scope with the same name as the crate.
-                    // If so, we have to disambiguate the potential import suggestions by making
-                    // the paths *global* (i.e., by prefixing them with `::`).
-                    let needs_disambiguation =
-                        self.resolutions(parent_scope.module).borrow().iter().any(
-                            |(key, name_resolution)| {
-                                if key.ns == TypeNS
-                                    && key.ident == ident
-                                    && let Some(binding) = name_resolution.borrow().binding
-                                {
-                                    match binding.res() {
-                                        // No disambiguation needed if the identically named item we
-                                        // found in scope actually refers to the crate in question.
-                                        Res::Def(_, def_id) => def_id != crate_def_id,
-                                        Res::PrimTy(_) => true,
-                                        _ => false,
-                                    }
-                                } else {
-                                    false
-                                }
-                            },
-                        );
-                    let mut crate_path = ThinVec::new();
-                    if needs_disambiguation {
-                        crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
-                    }
-                    crate_path.push(ast::PathSegment::from_ident(ident));
+                let Some(crate_id) = self.crate_loader(|c| c.maybe_process_path_extern(ident.name))
+                else {
+                    continue;
+                };
 
-                    suggestions.extend(self.lookup_import_candidates_from_module(
-                        lookup_ident,
-                        namespace,
-                        parent_scope,
-                        crate_root,
-                        crate_path,
-                        &filter_fn,
-                    ));
+                let crate_def_id = crate_id.as_def_id();
+                let crate_root = self.expect_module(crate_def_id);
+
+                // Check if there's already an item in scope with the same name as the crate.
+                // If so, we have to disambiguate the potential import suggestions by making
+                // the paths *global* (i.e., by prefixing them with `::`).
+                let needs_disambiguation =
+                    self.resolutions(parent_scope.module).borrow().iter().any(
+                        |(key, name_resolution)| {
+                            if key.ns == TypeNS
+                                && key.ident == ident
+                                && let Some(binding) = name_resolution.borrow().binding
+                            {
+                                match binding.res() {
+                                    // No disambiguation needed if the identically named item we
+                                    // found in scope actually refers to the crate in question.
+                                    Res::Def(_, def_id) => def_id != crate_def_id,
+                                    Res::PrimTy(_) => true,
+                                    _ => false,
+                                }
+                            } else {
+                                false
+                            }
+                        },
+                    );
+                let mut crate_path = ThinVec::new();
+                if needs_disambiguation {
+                    crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
                 }
+                crate_path.push(ast::PathSegment::from_ident(ident));
+
+                suggestions.extend(self.lookup_import_candidates_from_module(
+                    lookup_ident,
+                    namespace,
+                    parent_scope,
+                    crate_root,
+                    crate_path,
+                    &filter_fn,
+                ));
             }
         }
 
@@ -1511,7 +1503,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             });
         }
         for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
-            if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
+            let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
                 ident,
                 ScopeSet::All(ns),
                 parent_scope,
@@ -1519,53 +1511,53 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 false,
                 None,
                 None,
-            ) {
-                let desc = match binding.res() {
-                    Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
-                        "a function-like macro".to_string()
-                    }
-                    Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
-                        format!("an attribute: `#[{ident}]`")
-                    }
-                    Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
-                        format!("a derive macro: `#[derive({ident})]`")
-                    }
-                    Res::ToolMod => {
-                        // Don't confuse the user with tool modules.
-                        continue;
-                    }
-                    Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
-                        "only a trait, without a derive macro".to_string()
-                    }
-                    res => format!(
-                        "{} {}, not {} {}",
-                        res.article(),
-                        res.descr(),
-                        macro_kind.article(),
-                        macro_kind.descr_expected(),
-                    ),
-                };
-                if let crate::NameBindingKind::Import { import, .. } = binding.kind {
-                    if !import.span.is_dummy() {
-                        let note = errors::IdentImporterHereButItIsDesc {
-                            span: import.span,
-                            imported_ident: ident,
-                            imported_ident_desc: &desc,
-                        };
-                        err.subdiagnostic(note);
-                        // Silence the 'unused import' warning we might get,
-                        // since this diagnostic already covers that import.
-                        self.record_use(ident, binding, Used::Other);
-                        return;
-                    }
+            ) else {
+                continue;
+            };
+
+            let desc = match binding.res() {
+                Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(),
+                Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
+                    format!("an attribute: `#[{ident}]`")
+                }
+                Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
+                    format!("a derive macro: `#[derive({ident})]`")
                 }
-                let note = errors::IdentInScopeButItIsDesc {
+                Res::ToolMod => {
+                    // Don't confuse the user with tool modules.
+                    continue;
+                }
+                Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
+                    "only a trait, without a derive macro".to_string()
+                }
+                res => format!(
+                    "{} {}, not {} {}",
+                    res.article(),
+                    res.descr(),
+                    macro_kind.article(),
+                    macro_kind.descr_expected(),
+                ),
+            };
+            if let crate::NameBindingKind::Import { import, .. } = binding.kind
+                && !import.span.is_dummy()
+            {
+                let note = errors::IdentImporterHereButItIsDesc {
+                    span: import.span,
                     imported_ident: ident,
                     imported_ident_desc: &desc,
                 };
                 err.subdiagnostic(note);
+                // Silence the 'unused import' warning we might get,
+                // since this diagnostic already covers that import.
+                self.record_use(ident, binding, Used::Other);
                 return;
             }
+            let note = errors::IdentInScopeButItIsDesc {
+                imported_ident: ident,
+                imported_ident_desc: &desc,
+            };
+            err.subdiagnostic(note);
+            return;
         }
     }
 
@@ -1749,15 +1741,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     /// If the binding refers to a tuple struct constructor with fields,
     /// returns the span of its fields.
     fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option<Span> {
-        if let NameBindingKind::Res(Res::Def(
+        let NameBindingKind::Res(Res::Def(
             DefKind::Ctor(CtorOf::Struct, CtorKind::Fn),
             ctor_def_id,
         )) = binding.kind
-        {
-            let def_id = self.tcx.parent(ctor_def_id);
-            return self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to); // None for `struct Foo()`
-        }
-        None
+        else {
+            return None;
+        };
+
+        let def_id = self.tcx.parent(ctor_def_id);
+        self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to) // None for `struct Foo()`
     }
 
     fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) {
@@ -1983,10 +1976,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             .collect::<Vec<_>>();
         candidates.sort();
         candidates.dedup();
-        match find_best_match_for_name(&candidates, ident, None) {
-            Some(sugg) if sugg == ident => None,
-            sugg => sugg,
-        }
+        find_best_match_for_name(&candidates, ident, None).filter(|sugg| *sugg != ident)
     }
 
     pub(crate) fn report_path_resolution_error(
@@ -2044,13 +2034,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 (format!("`_` is not a valid crate or module name"), None)
             } else if self.tcx.sess.is_rust_2015() {
                 (
-                    format!("you might be missing crate `{ident}`"),
+                    format!("use of unresolved module or unlinked crate `{ident}`"),
                     Some((
                         vec![(
                             self.current_crate_outer_attr_insert_span,
                             format!("extern crate {ident};\n"),
                         )],
-                        format!("consider importing the `{ident}` crate"),
+                        if was_invoked_from_cargo() {
+                            format!(
+                                "if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
+                             to add it to your `Cargo.toml` and import it in your code",
+                            )
+                        } else {
+                            format!(
+                                "you might be missing a crate named `{ident}`, add it to your \
+                                 project and import it in your code",
+                            )
+                        },
                         Applicability::MaybeIncorrect,
                     )),
                 )
@@ -2229,20 +2229,37 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 let descr = binding.res().descr();
                 (format!("{descr} `{ident}` is not a crate or module"), suggestion)
             } else {
-                (format!("use of undeclared crate or module `{ident}`"), suggestion)
+                let suggestion = if suggestion.is_some() {
+                    suggestion
+                } else if was_invoked_from_cargo() {
+                    Some((
+                        vec![],
+                        format!(
+                            "if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
+                             to add it to your `Cargo.toml`",
+                        ),
+                        Applicability::MaybeIncorrect,
+                    ))
+                } else {
+                    Some((
+                        vec![],
+                        format!("you might be missing a crate named `{ident}`",),
+                        Applicability::MaybeIncorrect,
+                    ))
+                };
+                (format!("use of unresolved module or unlinked crate `{ident}`"), suggestion)
             }
         }
     }
 
     /// Adds suggestions for a path that cannot be resolved.
+    #[instrument(level = "debug", skip(self, parent_scope))]
     pub(crate) fn make_path_suggestion(
         &mut self,
         span: Span,
         mut path: Vec<Segment>,
         parent_scope: &ParentScope<'ra>,
     ) -> Option<(Vec<Segment>, Option<String>)> {
-        debug!("make_path_suggestion: span={:?} path={:?}", span, path);
-
         match (path.get(0), path.get(1)) {
             // `{{root}}::ident::...` on both editions.
             // On 2015 `{{root}}` is usually added implicitly.
@@ -2271,6 +2288,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     /// LL | use foo::Bar;
     ///    |     ^^^ did you mean `self::foo`?
     /// ```
+    #[instrument(level = "debug", skip(self, parent_scope))]
     fn make_missing_self_suggestion(
         &mut self,
         mut path: Vec<Segment>,
@@ -2279,7 +2297,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // Replace first ident with `self` and check if that is valid.
         path[0].ident.name = kw::SelfLower;
         let result = self.maybe_resolve_path(&path, None, parent_scope, None);
-        debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
+        debug!(?path, ?result);
         if let PathResult::Module(..) = result { Some((path, None)) } else { None }
     }
 
@@ -2290,6 +2308,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     /// LL | use foo::Bar;
     ///    |     ^^^ did you mean `crate::foo`?
     /// ```
+    #[instrument(level = "debug", skip(self, parent_scope))]
     fn make_missing_crate_suggestion(
         &mut self,
         mut path: Vec<Segment>,
@@ -2298,7 +2317,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // Replace first ident with `crate` and check if that is valid.
         path[0].ident.name = kw::Crate;
         let result = self.maybe_resolve_path(&path, None, parent_scope, None);
-        debug!("make_missing_crate_suggestion:  path={:?} result={:?}", path, result);
+        debug!(?path, ?result);
         if let PathResult::Module(..) = result {
             Some((
                 path,
@@ -2321,6 +2340,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     /// LL | use foo::Bar;
     ///    |     ^^^ did you mean `super::foo`?
     /// ```
+    #[instrument(level = "debug", skip(self, parent_scope))]
     fn make_missing_super_suggestion(
         &mut self,
         mut path: Vec<Segment>,
@@ -2329,7 +2349,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // Replace first ident with `crate` and check if that is valid.
         path[0].ident.name = kw::Super;
         let result = self.maybe_resolve_path(&path, None, parent_scope, None);
-        debug!("make_missing_super_suggestion:  path={:?} result={:?}", path, result);
+        debug!(?path, ?result);
         if let PathResult::Module(..) = result { Some((path, None)) } else { None }
     }
 
@@ -2343,6 +2363,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     ///
     /// Used when importing a submodule of an external crate but missing that crate's
     /// name as the first part of path.
+    #[instrument(level = "debug", skip(self, parent_scope))]
     fn make_external_crate_suggestion(
         &mut self,
         mut path: Vec<Segment>,
@@ -2363,10 +2384,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             // Replace first ident with a crate name and check if that is valid.
             path[0].ident.name = name;
             let result = self.maybe_resolve_path(&path, None, parent_scope, None);
-            debug!(
-                "make_external_crate_suggestion: name={:?} path={:?} result={:?}",
-                name, path, result
-            );
+            debug!(?path, ?name, ?result);
             if let PathResult::Module(..) = result {
                 return Some((path, None));
             }
@@ -2410,121 +2428,115 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         let binding_key = BindingKey::new(ident, MacroNS);
         let resolution = resolutions.get(&binding_key)?;
         let binding = resolution.borrow().binding()?;
-        if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() {
-            let module_name = crate_module.kind.name().unwrap();
-            let import_snippet = match import.kind {
-                ImportKind::Single { source, target, .. } if source != target => {
-                    format!("{source} as {target}")
-                }
-                _ => format!("{ident}"),
-            };
+        let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else {
+            return None;
+        };
+        let module_name = crate_module.kind.name().unwrap();
+        let import_snippet = match import.kind {
+            ImportKind::Single { source, target, .. } if source != target => {
+                format!("{source} as {target}")
+            }
+            _ => format!("{ident}"),
+        };
 
-            let mut corrections: Vec<(Span, String)> = Vec::new();
-            if !import.is_nested() {
-                // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove
-                // intermediate segments.
-                corrections.push((import.span, format!("{module_name}::{import_snippet}")));
-            } else {
-                // Find the binding span (and any trailing commas and spaces).
-                //   ie. `use a::b::{c, d, e};`
-                //                      ^^^
-                let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
-                    self.tcx.sess,
-                    import.span,
-                    import.use_span,
-                );
-                debug!(
-                    "check_for_module_export_macro: found_closing_brace={:?} binding_span={:?}",
-                    found_closing_brace, binding_span
-                );
+        let mut corrections: Vec<(Span, String)> = Vec::new();
+        if !import.is_nested() {
+            // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove
+            // intermediate segments.
+            corrections.push((import.span, format!("{module_name}::{import_snippet}")));
+        } else {
+            // Find the binding span (and any trailing commas and spaces).
+            //   ie. `use a::b::{c, d, e};`
+            //                      ^^^
+            let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
+                self.tcx.sess,
+                import.span,
+                import.use_span,
+            );
+            debug!(found_closing_brace, ?binding_span);
+
+            let mut removal_span = binding_span;
+
+            // If the binding span ended with a closing brace, as in the below example:
+            //   ie. `use a::b::{c, d};`
+            //                      ^
+            // Then expand the span of characters to remove to include the previous
+            // binding's trailing comma.
+            //   ie. `use a::b::{c, d};`
+            //                    ^^^
+            if found_closing_brace
+                && let Some(previous_span) =
+                    extend_span_to_previous_binding(self.tcx.sess, binding_span)
+            {
+                debug!(?previous_span);
+                removal_span = removal_span.with_lo(previous_span.lo());
+            }
+            debug!(?removal_span);
 
-                let mut removal_span = binding_span;
-                if found_closing_brace {
-                    // If the binding span ended with a closing brace, as in the below example:
-                    //   ie. `use a::b::{c, d};`
-                    //                      ^
-                    // Then expand the span of characters to remove to include the previous
-                    // binding's trailing comma.
-                    //   ie. `use a::b::{c, d};`
-                    //                    ^^^
-                    if let Some(previous_span) =
-                        extend_span_to_previous_binding(self.tcx.sess, binding_span)
-                    {
-                        debug!("check_for_module_export_macro: previous_span={:?}", previous_span);
-                        removal_span = removal_span.with_lo(previous_span.lo());
-                    }
-                }
-                debug!("check_for_module_export_macro: removal_span={:?}", removal_span);
-
-                // Remove the `removal_span`.
-                corrections.push((removal_span, "".to_string()));
-
-                // Find the span after the crate name and if it has nested imports immediately
-                // after the crate name already.
-                //   ie. `use a::b::{c, d};`
-                //               ^^^^^^^^^
-                //   or  `use a::{b, c, d}};`
-                //               ^^^^^^^^^^^
-                let (has_nested, after_crate_name) = find_span_immediately_after_crate_name(
-                    self.tcx.sess,
-                    module_name,
-                    import.use_span,
-                );
-                debug!(
-                    "check_for_module_export_macro: has_nested={:?} after_crate_name={:?}",
-                    has_nested, after_crate_name
-                );
+            // Remove the `removal_span`.
+            corrections.push((removal_span, "".to_string()));
 
-                let source_map = self.tcx.sess.source_map();
+            // Find the span after the crate name and if it has nested imports immediately
+            // after the crate name already.
+            //   ie. `use a::b::{c, d};`
+            //               ^^^^^^^^^
+            //   or  `use a::{b, c, d}};`
+            //               ^^^^^^^^^^^
+            let (has_nested, after_crate_name) =
+                find_span_immediately_after_crate_name(self.tcx.sess, module_name, import.use_span);
+            debug!(has_nested, ?after_crate_name);
 
-                // Make sure this is actually crate-relative.
-                let is_definitely_crate = import
-                    .module_path
-                    .first()
-                    .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
+            let source_map = self.tcx.sess.source_map();
 
-                // Add the import to the start, with a `{` if required.
-                let start_point = source_map.start_point(after_crate_name);
-                if is_definitely_crate
-                    && let Ok(start_snippet) = source_map.span_to_snippet(start_point)
-                {
-                    corrections.push((
-                        start_point,
-                        if has_nested {
-                            // In this case, `start_snippet` must equal '{'.
-                            format!("{start_snippet}{import_snippet}, ")
-                        } else {
-                            // In this case, add a `{`, then the moved import, then whatever
-                            // was there before.
-                            format!("{{{import_snippet}, {start_snippet}")
-                        },
-                    ));
+            // Make sure this is actually crate-relative.
+            let is_definitely_crate = import
+                .module_path
+                .first()
+                .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
 
-                    // Add a `};` to the end if nested, matching the `{` added at the start.
-                    if !has_nested {
-                        corrections
-                            .push((source_map.end_point(after_crate_name), "};".to_string()));
-                    }
-                } else {
-                    // If the root import is module-relative, add the import separately
-                    corrections.push((
-                        import.use_span.shrink_to_lo(),
-                        format!("use {module_name}::{import_snippet};\n"),
-                    ));
+            // Add the import to the start, with a `{` if required.
+            let start_point = source_map.start_point(after_crate_name);
+            if is_definitely_crate
+                && let Ok(start_snippet) = source_map.span_to_snippet(start_point)
+            {
+                corrections.push((
+                    start_point,
+                    if has_nested {
+                        // In this case, `start_snippet` must equal '{'.
+                        format!("{start_snippet}{import_snippet}, ")
+                    } else {
+                        // In this case, add a `{`, then the moved import, then whatever
+                        // was there before.
+                        format!("{{{import_snippet}, {start_snippet}")
+                    },
+                ));
+
+                // Add a `};` to the end if nested, matching the `{` added at the start.
+                if !has_nested {
+                    corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
                 }
+            } else {
+                // If the root import is module-relative, add the import separately
+                corrections.push((
+                    import.use_span.shrink_to_lo(),
+                    format!("use {module_name}::{import_snippet};\n"),
+                ));
             }
+        }
 
-            let suggestion = Some((
-                corrections,
-                String::from("a macro with this name exists at the root of the crate"),
-                Applicability::MaybeIncorrect,
-            ));
-            Some((suggestion, Some("this could be because a macro annotated with `#[macro_export]` will be exported \
+        let suggestion = Some((
+            corrections,
+            String::from("a macro with this name exists at the root of the crate"),
+            Applicability::MaybeIncorrect,
+        ));
+        Some((
+            suggestion,
+            Some(
+                "this could be because a macro annotated with `#[macro_export]` will be exported \
             at the root of the crate instead of the module where it is defined"
-               .to_string())))
-        } else {
-            None
-        }
+                    .to_string(),
+            ),
+        ))
     }
 
     /// Finds a cfg-ed out item inside `module` with the matching name.
@@ -2677,15 +2689,12 @@ fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option
 /// use foo::{a, b::{c, d}};
 /// //       ^^^^^^^^^^^^^^^ -- true
 /// ```
+#[instrument(level = "debug", skip(sess))]
 fn find_span_immediately_after_crate_name(
     sess: &Session,
     module_name: Symbol,
     use_span: Span,
 ) -> (bool, Span) {
-    debug!(
-        "find_span_immediately_after_crate_name: module_name={:?} use_span={:?}",
-        module_name, use_span
-    );
     let source_map = sess.source_map();
 
     // Using `use issue_59764::foo::{baz, makro};` as an example throughout..
@@ -3051,7 +3060,6 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
                 self.first_legal_span = Some(inject);
             }
             self.first_use_span = search_for_any_use_in_items(&c.items);
-            return;
         } else {
             visit::walk_crate(self, c);
         }
@@ -3065,7 +3073,6 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
                     self.first_legal_span = Some(inject);
                 }
                 self.first_use_span = search_for_any_use_in_items(items);
-                return;
             }
         } else {
             visit::walk_item(self, item);
@@ -3075,16 +3082,16 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
 
 fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
     for item in items {
-        if let ItemKind::Use(..) = item.kind {
-            if is_span_suitable_for_use_injection(item.span) {
-                let mut lo = item.span.lo();
-                for attr in &item.attrs {
-                    if attr.span.eq_ctxt(item.span) {
-                        lo = std::cmp::min(lo, attr.span.lo());
-                    }
+        if let ItemKind::Use(..) = item.kind
+            && is_span_suitable_for_use_injection(item.span)
+        {
+            let mut lo = item.span.lo();
+            for attr in &item.attrs {
+                if attr.span.eq_ctxt(item.span) {
+                    lo = std::cmp::min(lo, attr.span.lo());
                 }
-                return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
             }
+            return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
         }
     }
     None
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index e279d14704e..6ef4aa40725 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -118,37 +118,38 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
         let resolutions = self.r.resolutions(module);
 
         for (_, name_resolution) in resolutions.borrow().iter() {
-            if let Some(mut binding) = name_resolution.borrow().binding() {
-                // Set the given effective visibility level to `Level::Direct` and
-                // sets the rest of the `use` chain to `Level::Reexported` until
-                // we hit the actual exported item.
-                //
-                // If the binding is ambiguous, put the root ambiguity binding and all reexports
-                // leading to it into the table. They are used by the `ambiguous_glob_reexports`
-                // lint. For all bindings added to the table this way `is_ambiguity` returns true.
-                let is_ambiguity =
-                    |binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn;
-                let mut parent_id = ParentId::Def(module_id);
-                let mut warn_ambiguity = binding.warn_ambiguity;
-                while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
-                    self.update_import(binding, parent_id);
+            let Some(mut binding) = name_resolution.borrow().binding() else {
+                continue;
+            };
+            // Set the given effective visibility level to `Level::Direct` and
+            // sets the rest of the `use` chain to `Level::Reexported` until
+            // we hit the actual exported item.
+            //
+            // If the binding is ambiguous, put the root ambiguity binding and all reexports
+            // leading to it into the table. They are used by the `ambiguous_glob_reexports`
+            // lint. For all bindings added to the table this way `is_ambiguity` returns true.
+            let is_ambiguity =
+                |binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn;
+            let mut parent_id = ParentId::Def(module_id);
+            let mut warn_ambiguity = binding.warn_ambiguity;
+            while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
+                self.update_import(binding, parent_id);
 
-                    if is_ambiguity(binding, warn_ambiguity) {
-                        // Stop at the root ambiguity, further bindings in the chain should not
-                        // be reexported because the root ambiguity blocks any access to them.
-                        // (Those further bindings are most likely not ambiguities themselves.)
-                        break;
-                    }
-
-                    parent_id = ParentId::Import(binding);
-                    binding = nested_binding;
-                    warn_ambiguity |= nested_binding.warn_ambiguity;
-                }
-                if !is_ambiguity(binding, warn_ambiguity)
-                    && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local())
-                {
-                    self.update_def(def_id, binding.vis.expect_local(), parent_id);
+                if is_ambiguity(binding, warn_ambiguity) {
+                    // Stop at the root ambiguity, further bindings in the chain should not
+                    // be reexported because the root ambiguity blocks any access to them.
+                    // (Those further bindings are most likely not ambiguities themselves.)
+                    break;
                 }
+
+                parent_id = ParentId::Import(binding);
+                binding = nested_binding;
+                warn_ambiguity |= nested_binding.warn_ambiguity;
+            }
+            if !is_ambiguity(binding, warn_ambiguity)
+                && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local())
+            {
+                self.update_def(def_id, binding.vis.expect_local(), parent_id);
             }
         }
     }
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 3bfe98f7091..7eb795034b0 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -59,7 +59,7 @@ pub(crate) struct NameAlreadyUsedInParameterList {
     pub(crate) span: Span,
     #[label(resolve_first_use_of_name)]
     pub(crate) first_use_span: Span,
-    pub(crate) name: Symbol,
+    pub(crate) name: Ident,
 }
 
 #[derive(Diagnostic)]
@@ -142,7 +142,7 @@ pub(crate) struct VariableBoundWithDifferentMode {
     pub(crate) span: Span,
     #[label(resolve_first_binding_span)]
     pub(crate) first_binding_span: Span,
-    pub(crate) variable_name: Symbol,
+    pub(crate) variable_name: Ident,
 }
 
 #[derive(Diagnostic)]
@@ -151,7 +151,7 @@ pub(crate) struct IdentifierBoundMoreThanOnceInParameterList {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
-    pub(crate) identifier: Symbol,
+    pub(crate) identifier: Ident,
 }
 
 #[derive(Diagnostic)]
@@ -160,7 +160,7 @@ pub(crate) struct IdentifierBoundMoreThanOnceInSamePattern {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
-    pub(crate) identifier: Symbol,
+    pub(crate) identifier: Ident,
 }
 
 #[derive(Diagnostic)]
@@ -478,7 +478,7 @@ pub(crate) struct TraitImplDuplicate {
     pub(crate) old_span: Span,
     #[label(resolve_trait_item_span)]
     pub(crate) trait_item_span: Span,
-    pub(crate) name: Symbol,
+    pub(crate) name: Ident,
 }
 
 #[derive(Diagnostic)]
@@ -976,7 +976,7 @@ pub(crate) struct AttemptToDefineBuiltinMacroTwice {
 pub(crate) struct VariableIsNotBoundInAllPatterns {
     #[primary_span]
     pub(crate) multispan: MultiSpan,
-    pub(crate) name: Symbol,
+    pub(crate) name: Ident,
 }
 
 #[derive(Subdiagnostic, Debug, Clone)]
@@ -984,7 +984,7 @@ pub(crate) struct VariableIsNotBoundInAllPatterns {
 pub(crate) struct PatternDoesntBindName {
     #[primary_span]
     pub(crate) span: Span,
-    pub(crate) name: Symbol,
+    pub(crate) name: Ident,
 }
 
 #[derive(Subdiagnostic, Debug, Clone)]
@@ -1260,7 +1260,7 @@ pub(crate) struct TraitImplMismatch {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
-    pub(crate) name: Symbol,
+    pub(crate) name: Ident,
     pub(crate) kind: &'static str,
     pub(crate) trait_path: String,
     #[label(resolve_trait_impl_mismatch_label_item)]
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 45e87edc53e..a3d3e87ade0 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -246,23 +246,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // ---- end
         // ```
         // So we have to fall back to the module's parent during lexical resolution in this case.
-        if derive_fallback_lint_id.is_some() {
-            if let Some(parent) = module.parent {
-                // Inner module is inside the macro, parent module is outside of the macro.
-                if module.expansion != parent.expansion
-                    && module.expansion.is_descendant_of(parent.expansion)
-                {
-                    // The macro is a proc macro derive
-                    if let Some(def_id) = module.expansion.expn_data().macro_def_id {
-                        let ext = &self.get_macro_by_def_id(def_id).ext;
-                        if ext.builtin_name.is_none()
-                            && ext.macro_kind() == MacroKind::Derive
-                            && parent.expansion.outer_expn_is_descendant_of(*ctxt)
-                        {
-                            return Some((parent, derive_fallback_lint_id));
-                        }
-                    }
-                }
+        if derive_fallback_lint_id.is_some()
+            && let Some(parent) = module.parent
+            // Inner module is inside the macro
+            && module.expansion != parent.expansion
+            // Parent module is outside of the macro
+            && module.expansion.is_descendant_of(parent.expansion)
+            // The macro is a proc macro derive
+            && let Some(def_id) = module.expansion.expn_data().macro_def_id
+        {
+            let ext = &self.get_macro_by_def_id(def_id).ext;
+            if ext.builtin_name.is_none()
+                && ext.macro_kind() == MacroKind::Derive
+                && parent.expansion.outer_expn_is_descendant_of(*ctxt)
+            {
+                return Some((parent, derive_fallback_lint_id));
             }
         }
 
@@ -593,8 +591,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     },
                     Scope::StdLibPrelude => {
                         let mut result = Err(Determinacy::Determined);
-                        if let Some(prelude) = this.prelude {
-                            if let Ok(binding) = this.resolve_ident_in_module_unadjusted(
+                        if let Some(prelude) = this.prelude
+                            && let Ok(binding) = this.resolve_ident_in_module_unadjusted(
                                 ModuleOrUniformRoot::Module(prelude),
                                 ident,
                                 ns,
@@ -603,14 +601,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                                 None,
                                 ignore_binding,
                                 ignore_import,
-                            ) {
-                                if matches!(use_prelude, UsePrelude::Yes)
-                                    || this.is_builtin_macro(binding.res())
-                                {
-                                    result = Ok((binding, Flags::MISC_FROM_PRELUDE));
-                                }
-                            }
+                            )
+                            && (matches!(use_prelude, UsePrelude::Yes)
+                                || this.is_builtin_macro(binding.res()))
+                        {
+                            result = Ok((binding, Flags::MISC_FROM_PRELUDE));
                         }
+
                         result
                     }
                     Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) {
@@ -939,10 +936,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         };
 
         // Items and single imports are not shadowable, if we have one, then it's determined.
-        if let Some(binding) = binding {
-            if !binding.is_glob_import() {
-                return check_usable(self, binding);
-            }
+        if let Some(binding) = binding
+            && !binding.is_glob_import()
+        {
+            return check_usable(self, binding);
         }
 
         // --- From now on we either have a glob resolution or no resolution. ---
@@ -1437,13 +1434,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         for (segment_idx, &Segment { ident, id, .. }) in path.iter().enumerate() {
             debug!("resolve_path ident {} {:?} {:?}", segment_idx, ident, id);
             let record_segment_res = |this: &mut Self, res| {
-                if finalize.is_some() {
-                    if let Some(id) = id {
-                        if !this.partial_res_map.contains_key(&id) {
-                            assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
-                            this.record_partial_res(id, PartialRes::new(res));
-                        }
-                    }
+                if finalize.is_some()
+                    && let Some(id) = id
+                    && !this.partial_res_map.contains_key(&id)
+                {
+                    assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
+                    this.record_partial_res(id, PartialRes::new(res));
                 }
             };
 
@@ -1463,13 +1459,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                             _ => None,
                         },
                     };
-                    if let Some(self_module) = self_module {
-                        if let Some(parent) = self_module.parent {
-                            module = Some(ModuleOrUniformRoot::Module(
-                                self.resolve_self(&mut ctxt, parent),
-                            ));
-                            continue;
-                        }
+                    if let Some(self_module) = self_module
+                        && let Some(parent) = self_module.parent
+                    {
+                        module =
+                            Some(ModuleOrUniformRoot::Module(self.resolve_self(&mut ctxt, parent)));
+                        continue;
                     }
                     return PathResult::failed(
                         ident,
@@ -1644,13 +1639,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 }
                 Err(Undetermined) => return PathResult::Indeterminate,
                 Err(Determined) => {
-                    if let Some(ModuleOrUniformRoot::Module(module)) = module {
-                        if opt_ns.is_some() && !module.is_normal() {
-                            return PathResult::NonModule(PartialRes::with_unresolved_segments(
-                                module.res().unwrap(),
-                                path.len() - segment_idx,
-                            ));
-                        }
+                    if let Some(ModuleOrUniformRoot::Module(module)) = module
+                        && opt_ns.is_some()
+                        && !module.is_normal()
+                    {
+                        return PathResult::NonModule(PartialRes::with_unresolved_segments(
+                            module.res().unwrap(),
+                            path.len() - segment_idx,
+                        ));
                     }
 
                     return PathResult::failed(
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index cad45d3c293..d555c938770 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -287,12 +287,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             binding.vis
         };
 
-        if let ImportKind::Glob { ref max_vis, .. } = import.kind {
-            if vis == import_vis
-                || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self.tcx))
-            {
-                max_vis.set(Some(vis.expect_local()))
-            }
+        if let ImportKind::Glob { ref max_vis, .. } = import.kind
+            && (vis == import_vis
+                || max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx)))
+        {
+            max_vis.set(Some(vis.expect_local()))
         }
 
         self.arenas.alloc_name_binding(NameBindingData {
@@ -543,31 +542,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             // resolution for it so that later resolve stages won't complain.
             self.import_dummy_binding(*import, is_indeterminate);
 
-            if let Some(err) = unresolved_import_error {
-                glob_error |= import.is_glob();
+            let Some(err) = unresolved_import_error else { continue };
 
-                if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
-                    if source.name == kw::SelfLower {
-                        // Silence `unresolved import` error if E0429 is already emitted
-                        if let Err(Determined) = source_bindings.value_ns.get() {
-                            continue;
-                        }
-                    }
-                }
+            glob_error |= import.is_glob();
 
-                if prev_root_id != NodeId::ZERO
-                    && prev_root_id != import.root_id
-                    && !errors.is_empty()
-                {
-                    // In the case of a new import line, throw a diagnostic message
-                    // for the previous line.
-                    self.throw_unresolved_import_error(errors, glob_error);
-                    errors = vec![];
-                }
-                if seen_spans.insert(err.span) {
-                    errors.push((*import, err));
-                    prev_root_id = import.root_id;
-                }
+            if let ImportKind::Single { source, ref source_bindings, .. } = import.kind
+                && source.name == kw::SelfLower
+                // Silence `unresolved import` error if E0429 is already emitted
+                && let Err(Determined) = source_bindings.value_ns.get()
+            {
+                continue;
+            }
+
+            if prev_root_id != NodeId::ZERO && prev_root_id != import.root_id && !errors.is_empty()
+            {
+                // In the case of a new import line, throw a diagnostic message
+                // for the previous line.
+                self.throw_unresolved_import_error(errors, glob_error);
+                errors = vec![];
+            }
+            if seen_spans.insert(err.span) {
+                errors.push((*import, err));
+                prev_root_id = import.root_id;
             }
         }
 
@@ -609,60 +605,60 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             for (key, resolution) in self.resolutions(*module).borrow().iter() {
                 let resolution = resolution.borrow();
 
-                if let Some(binding) = resolution.binding {
-                    if let NameBindingKind::Import { import, .. } = binding.kind
-                        && let Some((amb_binding, _)) = binding.ambiguity
-                        && binding.res() != Res::Err
-                        && exported_ambiguities.contains(&binding)
+                let Some(binding) = resolution.binding else { continue };
+
+                if let NameBindingKind::Import { import, .. } = binding.kind
+                    && let Some((amb_binding, _)) = binding.ambiguity
+                    && binding.res() != Res::Err
+                    && exported_ambiguities.contains(&binding)
+                {
+                    self.lint_buffer.buffer_lint(
+                        AMBIGUOUS_GLOB_REEXPORTS,
+                        import.root_id,
+                        import.root_span,
+                        BuiltinLintDiag::AmbiguousGlobReexports {
+                            name: key.ident.to_string(),
+                            namespace: key.ns.descr().to_string(),
+                            first_reexport_span: import.root_span,
+                            duplicate_reexport_span: amb_binding.span,
+                        },
+                    );
+                }
+
+                if let Some(glob_binding) = resolution.shadowed_glob {
+                    let binding_id = match binding.kind {
+                        NameBindingKind::Res(res) => {
+                            Some(self.def_id_to_node_id[res.def_id().expect_local()])
+                        }
+                        NameBindingKind::Module(module) => {
+                            Some(self.def_id_to_node_id[module.def_id().expect_local()])
+                        }
+                        NameBindingKind::Import { import, .. } => import.id(),
+                    };
+
+                    if binding.res() != Res::Err
+                        && glob_binding.res() != Res::Err
+                        && let NameBindingKind::Import { import: glob_import, .. } =
+                            glob_binding.kind
+                        && let Some(binding_id) = binding_id
+                        && let Some(glob_import_id) = glob_import.id()
+                        && let glob_import_def_id = self.local_def_id(glob_import_id)
+                        && self.effective_visibilities.is_exported(glob_import_def_id)
+                        && glob_binding.vis.is_public()
+                        && !binding.vis.is_public()
                     {
                         self.lint_buffer.buffer_lint(
-                            AMBIGUOUS_GLOB_REEXPORTS,
-                            import.root_id,
-                            import.root_span,
-                            BuiltinLintDiag::AmbiguousGlobReexports {
-                                name: key.ident.to_string(),
-                                namespace: key.ns.descr().to_string(),
-                                first_reexport_span: import.root_span,
-                                duplicate_reexport_span: amb_binding.span,
+                            HIDDEN_GLOB_REEXPORTS,
+                            binding_id,
+                            binding.span,
+                            BuiltinLintDiag::HiddenGlobReexports {
+                                name: key.ident.name.to_string(),
+                                namespace: key.ns.descr().to_owned(),
+                                glob_reexport_span: glob_binding.span,
+                                private_item_span: binding.span,
                             },
                         );
                     }
-
-                    if let Some(glob_binding) = resolution.shadowed_glob {
-                        let binding_id = match binding.kind {
-                            NameBindingKind::Res(res) => {
-                                Some(self.def_id_to_node_id[res.def_id().expect_local()])
-                            }
-                            NameBindingKind::Module(module) => {
-                                Some(self.def_id_to_node_id[module.def_id().expect_local()])
-                            }
-                            NameBindingKind::Import { import, .. } => import.id(),
-                        };
-
-                        if binding.res() != Res::Err
-                            && glob_binding.res() != Res::Err
-                            && let NameBindingKind::Import { import: glob_import, .. } =
-                                glob_binding.kind
-                            && let Some(binding_id) = binding_id
-                            && let Some(glob_import_id) = glob_import.id()
-                            && let glob_import_def_id = self.local_def_id(glob_import_id)
-                            && self.effective_visibilities.is_exported(glob_import_def_id)
-                            && glob_binding.vis.is_public()
-                            && !binding.vis.is_public()
-                        {
-                            self.lint_buffer.buffer_lint(
-                                HIDDEN_GLOB_REEXPORTS,
-                                binding_id,
-                                binding.span,
-                                BuiltinLintDiag::HiddenGlobReexports {
-                                    name: key.ident.name.to_string(),
-                                    namespace: key.ns.descr().to_owned(),
-                                    glob_reexport_span: glob_binding.span,
-                                    private_item_span: binding.span,
-                                },
-                            );
-                        }
-                    }
                 }
             }
         }
@@ -1006,21 +1002,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         self.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
                     }
 
-                    if let ModuleOrUniformRoot::Module(module) = module {
-                        if module == import.parent_scope.module {
-                            // Importing a module into itself is not allowed.
-                            return Some(UnresolvedImportError {
-                                span: import.span,
-                                label: Some(String::from(
-                                    "cannot glob-import a module into itself",
-                                )),
-                                note: None,
-                                suggestion: None,
-                                candidates: None,
-                                segment: None,
-                                module: None,
-                            });
-                        }
+                    if let ModuleOrUniformRoot::Module(module) = module
+                        && module == import.parent_scope.module
+                    {
+                        // Importing a module into itself is not allowed.
+                        return Some(UnresolvedImportError {
+                            span: import.span,
+                            label: Some(String::from("cannot glob-import a module into itself")),
+                            note: None,
+                            suggestion: None,
+                            candidates: None,
+                            segment: None,
+                            module: None,
+                        });
                     }
                     if !is_prelude
                         && let Some(max_vis) = max_vis.get()
@@ -1081,18 +1075,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         // Consistency checks, analogous to `finalize_macro_resolutions`.
                         let initial_res = source_bindings[ns].get().map(|initial_binding| {
                             all_ns_err = false;
-                            if let Some(target_binding) = target_bindings[ns].get() {
-                                if target.name == kw::Underscore
-                                    && initial_binding.is_extern_crate()
-                                    && !initial_binding.is_import()
-                                {
-                                    let used = if import.module_path.is_empty() {
-                                        Used::Scope
-                                    } else {
-                                        Used::Other
-                                    };
-                                    this.record_use(ident, target_binding, used);
-                                }
+                            if let Some(target_binding) = target_bindings[ns].get()
+                                && target.name == kw::Underscore
+                                && initial_binding.is_extern_crate()
+                                && !initial_binding.is_import()
+                            {
+                                let used = if import.module_path.is_empty() {
+                                    Used::Scope
+                                } else {
+                                    Used::Other
+                                };
+                                this.record_use(ident, target_binding, used);
                             }
                             initial_binding.res()
                         });
@@ -1247,17 +1240,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         let mut any_successful_reexport = false;
         let mut crate_private_reexport = false;
         self.per_ns(|this, ns| {
-            if let Ok(binding) = source_bindings[ns].get() {
-                if !binding.vis.is_at_least(import.vis, this.tcx) {
-                    reexport_error = Some((ns, binding));
-                    if let ty::Visibility::Restricted(binding_def_id) = binding.vis {
-                        if binding_def_id.is_top_level_module() {
-                            crate_private_reexport = true;
-                        }
-                    }
-                } else {
-                    any_successful_reexport = true;
+            let Ok(binding) = source_bindings[ns].get() else {
+                return;
+            };
+
+            if !binding.vis.is_at_least(import.vis, this.tcx) {
+                reexport_error = Some((ns, binding));
+                if let ty::Visibility::Restricted(binding_def_id) = binding.vis
+                    && binding_def_id.is_top_level_module()
+                {
+                    crate_private_reexport = true;
                 }
+            } else {
+                any_successful_reexport = true;
             }
         });
 
@@ -1474,28 +1469,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // Since import resolution is finished, globs will not define any more names.
         *module.globs.borrow_mut() = Vec::new();
 
-        if let Some(def_id) = module.opt_def_id() {
-            let mut children = Vec::new();
-
-            module.for_each_child(self, |this, ident, _, binding| {
-                let res = binding.res().expect_non_local();
-                let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity;
-                if res != def::Res::Err && !error_ambiguity {
-                    let mut reexport_chain = SmallVec::new();
-                    let mut next_binding = binding;
-                    while let NameBindingKind::Import { binding, import, .. } = next_binding.kind {
-                        reexport_chain.push(import.simplify(this));
-                        next_binding = binding;
-                    }
+        let Some(def_id) = module.opt_def_id() else { return };
+
+        let mut children = Vec::new();
 
-                    children.push(ModChild { ident, res, vis: binding.vis, reexport_chain });
+        module.for_each_child(self, |this, ident, _, binding| {
+            let res = binding.res().expect_non_local();
+            let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity;
+            if res != def::Res::Err && !error_ambiguity {
+                let mut reexport_chain = SmallVec::new();
+                let mut next_binding = binding;
+                while let NameBindingKind::Import { binding, import, .. } = next_binding.kind {
+                    reexport_chain.push(import.simplify(this));
+                    next_binding = binding;
                 }
-            });
 
-            if !children.is_empty() {
-                // Should be fine because this code is only called for local modules.
-                self.module_children.insert(def_id.expect_local(), children);
+                children.push(ModChild { ident, res, vis: binding.vis, reexport_chain });
             }
+        });
+
+        if !children.is_empty() {
+            // Should be fine because this code is only called for local modules.
+            self.module_children.insert(def_id.expect_local(), children);
         }
     }
 }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 1a0292ebbde..68d3351f174 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -468,16 +468,12 @@ impl<'a> PathSource<'a> {
                     {
                         "external crate"
                     }
-                    ExprKind::Path(_, path) => {
-                        let mut msg = "function";
-                        if let Some(segment) = path.segments.iter().last() {
-                            if let Some(c) = segment.ident.to_string().chars().next() {
-                                if c.is_uppercase() {
-                                    msg = "function, tuple struct or tuple variant";
-                                }
-                            }
-                        }
-                        msg
+                    ExprKind::Path(_, path)
+                        if let Some(segment) = path.segments.last()
+                            && let Some(c) = segment.ident.to_string().chars().next()
+                            && c.is_uppercase() =>
+                    {
+                        "function, tuple struct or tuple variant"
                     }
                     _ => "function",
                 },
@@ -612,7 +608,7 @@ impl MaybeExported<'_> {
                 return vis.kind.is_pub();
             }
         };
-        def_id.map_or(true, |def_id| r.effective_visibilities.is_exported(def_id))
+        def_id.is_none_or(|def_id| r.effective_visibilities.is_exported(def_id))
     }
 }
 
@@ -1182,32 +1178,27 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
                 // namespace first, and if that fails we try again in the value namespace. If
                 // resolution in the value namespace succeeds, we have an generic const argument on
                 // our hands.
-                if let TyKind::Path(None, ref path) = ty.kind {
+                if let TyKind::Path(None, ref path) = ty.kind
                     // We cannot disambiguate multi-segment paths right now as that requires type
                     // checking.
-                    if path.is_potential_trivial_const_arg() {
-                        let mut check_ns = |ns| {
-                            self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
-                                .is_some()
-                        };
-                        if !check_ns(TypeNS) && check_ns(ValueNS) {
-                            self.resolve_anon_const_manual(
-                                true,
-                                AnonConstKind::ConstArg(IsRepeatExpr::No),
-                                |this| {
-                                    this.smart_resolve_path(
-                                        ty.id,
-                                        &None,
-                                        path,
-                                        PathSource::Expr(None),
-                                    );
-                                    this.visit_path(path, ty.id);
-                                },
-                            );
+                    && path.is_potential_trivial_const_arg()
+                {
+                    let mut check_ns = |ns| {
+                        self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
+                            .is_some()
+                    };
+                    if !check_ns(TypeNS) && check_ns(ValueNS) {
+                        self.resolve_anon_const_manual(
+                            true,
+                            AnonConstKind::ConstArg(IsRepeatExpr::No),
+                            |this| {
+                                this.smart_resolve_path(ty.id, &None, path, PathSource::Expr(None));
+                                this.visit_path(path, ty.id);
+                            },
+                        );
 
-                            self.diag_metadata.currently_processing_generic_args = prev;
-                            return;
-                        }
+                        self.diag_metadata.currently_processing_generic_args = prev;
+                        return;
                     }
                 }
 
@@ -1243,54 +1234,56 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
     }
 
     fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) {
-        if let Some(ref args) = path_segment.args {
-            match &**args {
-                GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, args),
-                GenericArgs::Parenthesized(p_args) => {
-                    // Probe the lifetime ribs to know how to behave.
-                    for rib in self.lifetime_ribs.iter().rev() {
-                        match rib.kind {
-                            // We are inside a `PolyTraitRef`. The lifetimes are
-                            // to be introduced in that (maybe implicit) `for<>` binder.
-                            LifetimeRibKind::Generics {
-                                binder,
-                                kind: LifetimeBinderKind::PolyTrait,
-                                ..
-                            } => {
-                                self.with_lifetime_rib(
-                                    LifetimeRibKind::AnonymousCreateParameter {
+        let Some(ref args) = path_segment.args else {
+            return;
+        };
+
+        match &**args {
+            GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, args),
+            GenericArgs::Parenthesized(p_args) => {
+                // Probe the lifetime ribs to know how to behave.
+                for rib in self.lifetime_ribs.iter().rev() {
+                    match rib.kind {
+                        // We are inside a `PolyTraitRef`. The lifetimes are
+                        // to be introduced in that (maybe implicit) `for<>` binder.
+                        LifetimeRibKind::Generics {
+                            binder,
+                            kind: LifetimeBinderKind::PolyTrait,
+                            ..
+                        } => {
+                            self.with_lifetime_rib(
+                                LifetimeRibKind::AnonymousCreateParameter {
+                                    binder,
+                                    report_in_path: false,
+                                },
+                                |this| {
+                                    this.resolve_fn_signature(
                                         binder,
-                                        report_in_path: false,
-                                    },
-                                    |this| {
-                                        this.resolve_fn_signature(
-                                            binder,
-                                            false,
-                                            p_args.inputs.iter().map(|ty| (None, &**ty)),
-                                            &p_args.output,
-                                        )
-                                    },
-                                );
-                                break;
-                            }
-                            // We have nowhere to introduce generics. Code is malformed,
-                            // so use regular lifetime resolution to avoid spurious errors.
-                            LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => {
-                                visit::walk_generic_args(self, args);
-                                break;
-                            }
-                            LifetimeRibKind::AnonymousCreateParameter { .. }
-                            | LifetimeRibKind::AnonymousReportError
-                            | LifetimeRibKind::StaticIfNoLifetimeInScope { .. }
-                            | LifetimeRibKind::Elided(_)
-                            | LifetimeRibKind::ElisionFailure
-                            | LifetimeRibKind::ConcreteAnonConst(_)
-                            | LifetimeRibKind::ConstParamTy => {}
+                                        false,
+                                        p_args.inputs.iter().map(|ty| (None, &**ty)),
+                                        &p_args.output,
+                                    )
+                                },
+                            );
+                            break;
+                        }
+                        // We have nowhere to introduce generics. Code is malformed,
+                        // so use regular lifetime resolution to avoid spurious errors.
+                        LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => {
+                            visit::walk_generic_args(self, args);
+                            break;
                         }
+                        LifetimeRibKind::AnonymousCreateParameter { .. }
+                        | LifetimeRibKind::AnonymousReportError
+                        | LifetimeRibKind::StaticIfNoLifetimeInScope { .. }
+                        | LifetimeRibKind::Elided(_)
+                        | LifetimeRibKind::ElisionFailure
+                        | LifetimeRibKind::ConcreteAnonConst(_)
+                        | LifetimeRibKind::ConstParamTy => {}
                     }
                 }
-                GenericArgs::ParenthesizedElided(_) => {}
             }
+            GenericArgs::ParenthesizedElided(_) => {}
         }
     }
 
@@ -1735,13 +1728,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         }
 
         let normalized_ident = ident.normalize_to_macros_2_0();
-        let mut outer_res = None;
-        for rib in lifetime_rib_iter {
-            if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) {
-                outer_res = Some(outer);
-                break;
-            }
-        }
+        let outer_res = lifetime_rib_iter
+            .find_map(|rib| rib.bindings.get_key_value(&normalized_ident).map(|(&outer, _)| outer));
 
         self.emit_undeclared_lifetime_error(lifetime, outer_res);
         self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named);
@@ -1808,23 +1796,21 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 }
                 LifetimeRibKind::AnonymousReportError => {
                     if elided {
-                        let mut suggestion = None;
-                        for rib in self.lifetime_ribs[i..].iter().rev() {
+                        let suggestion = self.lifetime_ribs[i..].iter().rev().find_map(|rib| {
                             if let LifetimeRibKind::Generics {
                                 span,
                                 kind: LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound,
                                 ..
-                            } = &rib.kind
+                            } = rib.kind
                             {
-                                suggestion =
-                                    Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion {
-                                        lo: span.shrink_to_lo(),
-                                        hi: lifetime.ident.span.shrink_to_hi(),
-                                    });
-                                break;
+                                Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion {
+                                    lo: span.shrink_to_lo(),
+                                    hi: lifetime.ident.span.shrink_to_hi(),
+                                })
+                            } else {
+                                None
                             }
-                        }
-
+                        });
                         // are we trying to use an anonymous lifetime
                         // on a non GAT associated trait type?
                         if !self.in_func_body
@@ -2460,12 +2446,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         for i in (0..self.label_ribs.len()).rev() {
             let rib = &self.label_ribs[i];
 
-            if let RibKind::MacroDefinition(def) = rib.kind {
+            if let RibKind::MacroDefinition(def) = rib.kind
                 // If an invocation of this macro created `ident`, give up on `ident`
                 // and switch to `ident`'s source from the macro definition.
-                if def == self.r.macro_def(label.span.ctxt()) {
-                    label.span.remove_mark();
-                }
+                && def == self.r.macro_def(label.span.ctxt())
+            {
+                label.span.remove_mark();
             }
 
             let ident = label.normalize_to_macro_rules();
@@ -2493,14 +2479,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
     /// Determine whether or not a label from the `rib_index`th label rib is reachable.
     fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
         let ribs = &self.label_ribs[rib_index + 1..];
-
-        for rib in ribs {
-            if rib.kind.is_label_barrier() {
-                return false;
-            }
-        }
-
-        true
+        ribs.iter().all(|rib| !rib.kind.is_label_barrier())
     }
 
     fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
@@ -2856,7 +2835,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 match seen_bindings.entry(ident) {
                     Entry::Occupied(entry) => {
                         let span = *entry.get();
-                        let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
+                        let err = ResolutionError::NameAlreadyUsedInParameterList(ident, span);
                         self.report_error(param.ident.span, err);
                         let rib = match param.kind {
                             GenericParamKind::Lifetime => {
@@ -3443,7 +3422,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         match seen_trait_items.entry(id_in_trait) {
             Entry::Occupied(entry) => {
                 self.report_error(span, ResolutionError::TraitImplDuplicate {
-                    name: ident.name,
+                    name: ident,
                     old_span: *entry.get(),
                     trait_item_span: binding.span,
                 });
@@ -3478,7 +3457,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         };
         let trait_path = path_names_to_string(path);
         self.report_error(span, ResolutionError::TraitImplMismatch {
-            name: ident.name,
+            name: ident,
             kind,
             code,
             trait_path,
@@ -3505,21 +3484,20 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
             self.visit_ty(&qself.ty);
         }
         self.visit_path(&delegation.path, delegation.id);
-        if let Some(body) = &delegation.body {
-            self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
-                // `PatBoundCtx` is not necessary in this context
-                let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
-
-                let span = delegation.path.segments.last().unwrap().ident.span;
-                this.fresh_binding(
-                    Ident::new(kw::SelfLower, span),
-                    delegation.id,
-                    PatternSource::FnParam,
-                    &mut bindings,
-                );
-                this.visit_block(body);
-            });
-        }
+        let Some(body) = &delegation.body else { return };
+        self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
+            // `PatBoundCtx` is not necessary in this context
+            let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
+
+            let span = delegation.path.segments.last().unwrap().ident.span;
+            this.fresh_binding(
+                Ident::new(kw::SelfLower, span),
+                delegation.id,
+                PatternSource::FnParam,
+                &mut bindings,
+            );
+            this.visit_block(body);
+        });
     }
 
     fn resolve_params(&mut self, params: &'ast [Param]) {
@@ -3662,9 +3640,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 .filter(|(_, pat)| pat.id != pat_outer.id)
                 .flat_map(|(map, _)| map);
 
-            for (key, binding_inner) in inners {
-                let name = key.name;
-                match map_outer.get(key) {
+            for (&name, binding_inner) in inners {
+                match map_outer.get(&name) {
                     None => {
                         // The inner binding is missing in the outer.
                         let binding_error =
@@ -3902,7 +3879,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 // `Variant(a, a)`:
                 _ => IdentifierBoundMoreThanOnceInSamePattern,
             };
-            self.report_error(ident.span, error(ident.name));
+            self.report_error(ident.span, error(ident));
         }
 
         // Record as bound if it's valid:
@@ -5104,7 +5081,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 fn def_id_matches_path(tcx: TyCtxt<'_>, mut def_id: DefId, expected_path: &[&str]) -> bool {
     let mut path = expected_path.iter().rev();
     while let (Some(parent), Some(next_step)) = (tcx.opt_parent(def_id), path.next()) {
-        if !tcx.opt_item_name(def_id).map_or(false, |n| n.as_str() == *next_step) {
+        if !tcx.opt_item_name(def_id).is_some_and(|n| n.as_str() == *next_step) {
             return false;
         }
         def_id = parent;
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 2936d722aa7..2db8087fd83 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1636,13 +1636,12 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                                         .enumerate()
                                         .map(|(idx, new)| (new, old_fields.get(idx)))
                                         .map(|(new, old)| {
-                                            let new = new.name.to_ident_string();
                                             if let Some(Some(old)) = old
-                                                && new != *old
+                                                && new.as_str() != old
                                             {
                                                 format!("{new}: {old}")
                                             } else {
-                                                new
+                                                new.to_string()
                                             }
                                         })
                                         .collect::<Vec<String>>()
@@ -1696,7 +1695,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
             ) => {
                 // Don't suggest macro if it's unstable.
                 let suggestable = def_id.is_local()
-                    || self.r.tcx.lookup_stability(def_id).map_or(true, |s| s.is_stable());
+                    || self.r.tcx.lookup_stability(def_id).is_none_or(|s| s.is_stable());
 
                 err.span_label(span, fallback_label.to_string());
 
@@ -2135,7 +2134,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                                 .r
                                 .delegation_fn_sigs
                                 .get(&self.r.local_def_id(assoc_item.id))
-                                .map_or(false, |sig| sig.has_self) =>
+                                .is_some_and(|sig| sig.has_self) =>
                         {
                             AssocSuggestion::MethodWithSelf { called }
                         }
@@ -2166,7 +2165,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                                     .r
                                     .delegation_fn_sigs
                                     .get(&def_id)
-                                    .map_or(false, |sig| sig.has_self),
+                                    .is_some_and(|sig| sig.has_self),
                                 None => self
                                     .r
                                     .tcx
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 8e457e68eec..04144eb616f 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -214,7 +214,7 @@ enum Used {
 
 #[derive(Debug)]
 struct BindingError {
-    name: Symbol,
+    name: Ident,
     origin: BTreeSet<Span>,
     target: BTreeSet<Span>,
     could_be_path: bool,
@@ -226,7 +226,7 @@ enum ResolutionError<'ra> {
     GenericParamsFromOuterItem(Res, HasGenericParams, DefKind),
     /// Error E0403: the name is already used for a type or const parameter in this generic
     /// parameter list.
-    NameAlreadyUsedInParameterList(Symbol, Span),
+    NameAlreadyUsedInParameterList(Ident, Span),
     /// Error E0407: method is not a member of trait.
     MethodNotMemberOfTrait(Ident, String, Option<Symbol>),
     /// Error E0437: type is not a member of trait.
@@ -236,11 +236,11 @@ enum ResolutionError<'ra> {
     /// Error E0408: variable `{}` is not bound in all patterns.
     VariableNotBoundInPattern(BindingError, ParentScope<'ra>),
     /// Error E0409: variable `{}` is bound in inconsistent ways within the same match arm.
-    VariableBoundWithDifferentMode(Symbol, Span),
+    VariableBoundWithDifferentMode(Ident, Span),
     /// Error E0415: identifier is bound more than once in this parameter list.
-    IdentifierBoundMoreThanOnceInParameterList(Symbol),
+    IdentifierBoundMoreThanOnceInParameterList(Ident),
     /// Error E0416: identifier is bound more than once in the same pattern.
-    IdentifierBoundMoreThanOnceInSamePattern(Symbol),
+    IdentifierBoundMoreThanOnceInSamePattern(Ident),
     /// Error E0426: use of undeclared label.
     UndeclaredLabel { name: Symbol, suggestion: Option<LabelSuggestion> },
     /// Error E0429: `self` imports are only allowed within a `{ }` list.
@@ -292,14 +292,14 @@ enum ResolutionError<'ra> {
     UnreachableLabel { name: Symbol, definition_span: Span, suggestion: Option<LabelSuggestion> },
     /// Error E0323, E0324, E0325: mismatch between trait item and impl item.
     TraitImplMismatch {
-        name: Symbol,
+        name: Ident,
         kind: &'static str,
         trait_path: String,
         trait_item_span: Span,
         code: ErrCode,
     },
     /// Error E0201: multiple impl items for the same trait item.
-    TraitImplDuplicate { name: Symbol, trait_item_span: Span, old_span: Span },
+    TraitImplDuplicate { name: Ident, trait_item_span: Span, old_span: Span },
     /// Inline asm `sym` operand must refer to a `fn` or `static`.
     InvalidAsmSym,
     /// `self` used instead of `Self` in a generic parameter
@@ -1242,7 +1242,7 @@ impl<'ra> ResolverArenas<'ra> {
             no_implicit_prelude,
         ))));
         let def_id = module.opt_def_id();
-        if def_id.map_or(true, |def_id| def_id.is_local()) {
+        if def_id.is_none_or(|def_id| def_id.is_local()) {
             self.local_modules.borrow_mut().push(module);
         }
         if let Some(def_id) = def_id {
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index b6b2971263a..4ff54f47435 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -1022,7 +1022,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         span: Span,
     ) {
         if let Some(Res::NonMacroAttr(kind)) = res {
-            if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) {
+            if kind != NonMacroAttrKind::Tool && binding.is_none_or(|b| b.is_import()) {
                 let binding_span = binding.map(|binding| binding.span);
                 self.dcx().emit_err(errors::CannotUseThroughAnImport {
                     span,
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index 7998596c59e..fecb9735019 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -350,10 +350,7 @@ pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGen
 /// If there are no doc-comments, return true.
 /// FIXME(#78591): Support both inner and outer attributes on the same item.
 pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool {
-    attrs
-        .iter()
-        .find(|a| a.doc_str().is_some())
-        .map_or(true, |a| a.style() == ast::AttrStyle::Inner)
+    attrs.iter().find(|a| a.doc_str().is_some()).is_none_or(|a| a.style() == ast::AttrStyle::Inner)
 }
 
 /// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`.
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index e9983699609..b9c535df4bd 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -31,7 +31,7 @@ libc = "0.2"
 # tidy-alphabetical-end
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.57.0"
+version = "0.59.0"
 features = [
     "Win32_Foundation",
     "Win32_System_LibraryLoader",
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 21afb7df7cb..97bd2670aa6 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -675,7 +675,7 @@ impl OutputTypes {
 
     /// Returns `true` if user specified a name and not just produced type
     pub fn contains_explicit_name(&self, key: &OutputType) -> bool {
-        self.0.get(key).map_or(false, |f| f.is_some())
+        matches!(self.0.get(key), Some(Some(..)))
     }
 
     pub fn iter(&self) -> BTreeMapIter<'_, OutputType, Option<OutFileName>> {
@@ -888,7 +888,7 @@ impl Input {
             Input::File(file) => Some(file),
             Input::Str { name, .. } => match name {
                 FileName::Real(real) => real.local_path(),
-                FileName::QuoteExpansion(_) => None,
+                FileName::CfgSpec(_) => None,
                 FileName::Anon(_) => None,
                 FileName::MacroExpansion(_) => None,
                 FileName::ProcMacroSourceCode(_) => None,
@@ -1268,7 +1268,6 @@ pub enum EntryFnType {
         /// and an `include!()`.
         sigpipe: u8,
     },
-    Start,
 }
 
 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
@@ -1346,8 +1345,12 @@ pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
     user_cfg
 }
 
-pub fn build_target_config(early_dcx: &EarlyDiagCtxt, opts: &Options, sysroot: &Path) -> Target {
-    match Target::search(&opts.target_triple, sysroot) {
+pub fn build_target_config(
+    early_dcx: &EarlyDiagCtxt,
+    target: &TargetTuple,
+    sysroot: &Path,
+) -> Target {
+    match Target::search(target, sysroot) {
         Ok((target, warnings)) => {
             for warning in warnings.warning_messages() {
                 early_dcx.early_warn(warning)
@@ -1951,7 +1954,7 @@ fn collect_print_requests(
     matches: &getopts::Matches,
 ) -> Vec<PrintRequest> {
     let mut prints = Vec::<PrintRequest>::new();
-    if cg.target_cpu.as_ref().is_some_and(|s| s == "help") {
+    if cg.target_cpu.as_deref() == Some("help") {
         prints.push(PrintRequest { kind: PrintKind::TargetCPUs, out: OutFileName::Stdout });
         cg.target_cpu = None;
     };
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 4be013fd6fd..ec83761da4a 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -145,7 +145,7 @@ fn current_dll_path() -> Result<PathBuf, String> {
     .map_err(|e| e.to_string())?;
 
     let mut filename = vec![0; 1024];
-    let n = unsafe { GetModuleFileNameW(module, &mut filename) } as usize;
+    let n = unsafe { GetModuleFileNameW(Some(module), &mut filename) } as usize;
     if n == 0 {
         return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error()));
     }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 60f1154dc6d..1f03de3f53d 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -189,7 +189,7 @@ pub struct Session {
     /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with
     /// internal features are wontfix, and they are usually the cause of the ICEs.
     /// None signifies that this is not tracked.
-    pub using_internal_features: Arc<AtomicBool>,
+    pub using_internal_features: &'static AtomicBool,
 
     /// All commandline args used to invoke the compiler, with @file args fully expanded.
     /// This will only be used within debug info, e.g. in the pdb file on windows
@@ -895,13 +895,16 @@ fn default_emitter(
         }
         t => t,
     };
+
+    let source_map = if sopts.unstable_opts.link_only { None } else { Some(source_map) };
+
     match sopts.error_format {
         config::ErrorOutputType::HumanReadable(kind, color_config) => {
             let short = kind.short();
 
             if let HumanReadableErrorType::AnnotateSnippet = kind {
                 let emitter = AnnotateSnippetEmitter::new(
-                    Some(source_map),
+                    source_map,
                     bundle,
                     fallback_bundle,
                     short,
@@ -911,7 +914,7 @@ fn default_emitter(
             } else {
                 let emitter = HumanEmitter::new(stderr_destination(color_config), fallback_bundle)
                     .fluent_bundle(bundle)
-                    .sm(Some(source_map))
+                    .sm(source_map)
                     .short_message(short)
                     .teach(sopts.unstable_opts.teach)
                     .diagnostic_width(sopts.diagnostic_width)
@@ -966,7 +969,7 @@ pub fn build_session(
     sysroot: PathBuf,
     cfg_version: &'static str,
     ice_file: Option<PathBuf>,
-    using_internal_features: Arc<AtomicBool>,
+    using_internal_features: &'static AtomicBool,
     expanded_args: Vec<String>,
 ) -> Session {
     // FIXME: This is not general enough to make the warning lint completely override
@@ -1442,7 +1445,7 @@ fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> {
         config::ErrorOutputType::Json { pretty, json_rendered, color_config } => {
             Box::new(JsonEmitter::new(
                 Box::new(io::BufWriter::new(io::stderr())),
-                Lrc::new(SourceMap::new(FilePathMapping::empty())),
+                Some(Lrc::new(SourceMap::new(FilePathMapping::empty()))),
                 fallback_bundle,
                 pretty,
                 json_rendered,
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index dc63ea1999e..ad38ea228bf 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -316,7 +316,7 @@ macro_rules! optional {
 #[doc(hidden)]
 macro_rules! run_driver {
     ($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{
-        use rustc_driver::{Callbacks, Compilation, RunCompiler};
+        use rustc_driver::{Callbacks, Compilation, run_compiler};
         use rustc_middle::ty::TyCtxt;
         use rustc_interface::interface;
         use stable_mir::CompilerError;
@@ -347,7 +347,7 @@ macro_rules! run_driver {
             /// Runs the compiler against given target and tests it with `test_function`
             pub fn run(&mut self) -> Result<C, CompilerError<B>> {
                 let compiler_result = rustc_driver::catch_fatal_errors(|| -> interface::Result::<()> {
-                    RunCompiler::new(&self.args.clone(), self).run();
+                    run_compiler(&self.args.clone(), self);
                     Ok(())
                 });
                 match (compiler_result, self.result.take()) {
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index 9793a4d4162..31c7e6c3eb4 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -451,16 +451,13 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let ty = ty::Ty::new_static_str(tcx);
         let bytes = value.as_bytes();
         let val_tree = ty::ValTree::from_raw_bytes(tcx, bytes);
-
-        let ct = ty::Const::new_value(tcx, val_tree, ty);
-        super::convert::mir_const_from_ty_const(&mut *tables, ct, ty)
+        let val = tcx.valtree_to_const_val((ty, val_tree));
+        mir::Const::from_value(val, ty).stable(&mut tables)
     }
 
     fn new_const_bool(&self, value: bool) -> MirConst {
         let mut tables = self.0.borrow_mut();
-        let ct = ty::Const::from_bool(tables.tcx, value);
-        let ty = tables.tcx.types.bool;
-        super::convert::mir_const_from_ty_const(&mut *tables, ct, ty)
+        mir::Const::from_bool(tables.tcx, value).stable(&mut tables)
     }
 
     fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error> {
@@ -472,13 +469,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
             .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
             .unwrap()
             .size;
-
-        // We don't use Const::from_bits since it doesn't have any error checking.
         let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| {
             Error::new(format!("Value overflow: cannot convert `{value}` to `{ty}`."))
         })?;
-        let ct = ty::Const::new_value(tables.tcx, ValTree::from_scalar_int(scalar), ty);
-        Ok(super::convert::mir_const_from_ty_const(&mut *tables, ct, ty))
+        Ok(mir::Const::from_scalar(tcx, mir::interpret::Scalar::Int(scalar), ty)
+            .stable(&mut tables))
     }
     fn try_new_ty_const_uint(
         &self,
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
index 4f8da08eff9..a3da563af50 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
@@ -9,8 +9,6 @@ mod error;
 mod mir;
 mod ty;
 
-pub(crate) use ty::mir_const_from_ty_const;
-
 impl<'tcx> Stable<'tcx> for rustc_hir::Safety {
     type T = stable_mir::mir::Safety;
     fn stable(&self, _: &mut Tables<'_>) -> Self::T {
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index a7e122639ea..ff452eea23d 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -414,48 +414,6 @@ impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> {
     }
 }
 
-pub(crate) fn mir_const_from_ty_const<'tcx>(
-    tables: &mut Tables<'tcx>,
-    ty_const: ty::Const<'tcx>,
-    ty: Ty<'tcx>,
-) -> stable_mir::ty::MirConst {
-    let kind = match ty_const.kind() {
-        ty::ConstKind::Value(ty, val) => {
-            let val = match val {
-                ty::ValTree::Leaf(scalar) => ty::ValTree::Leaf(scalar),
-                ty::ValTree::Branch(branch) => {
-                    ty::ValTree::Branch(tables.tcx.lift(branch).unwrap())
-                }
-            };
-            let ty = tables.tcx.lift(ty).unwrap();
-            let const_val = tables.tcx.valtree_to_const_val((ty, val));
-            if matches!(const_val, mir::ConstValue::ZeroSized) {
-                stable_mir::ty::ConstantKind::ZeroSized
-            } else {
-                stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(
-                    ty, const_val, tables,
-                ))
-            }
-        }
-        ty::ConstKind::Param(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)),
-        ty::ConstKind::Error(_) => unreachable!(),
-        ty::ConstKind::Infer(_) => unreachable!(),
-        ty::ConstKind::Bound(_, _) => unimplemented!(),
-        ty::ConstKind::Placeholder(_) => unimplemented!(),
-        ty::ConstKind::Unevaluated(uv) => {
-            stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
-                def: tables.const_def(uv.def),
-                args: uv.args.stable(tables),
-                promoted: None,
-            })
-        }
-        ty::ConstKind::Expr(_) => unimplemented!(),
-    };
-    let stable_ty = tables.intern_ty(ty);
-    let id = tables.intern_mir_const(mir::Const::Ty(ty, ty_const));
-    stable_mir::ty::MirConst::new(kind, stable_ty, id)
-}
-
 impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
     type T = stable_mir::ty::TyConst;
 
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 51cfbf59471..51d809bd65d 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -25,6 +25,7 @@
 #![feature(hash_set_entry)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
+#![feature(map_try_insert)]
 #![feature(negative_impls)]
 #![feature(read_buf)]
 #![feature(round_char_boundary)]
@@ -85,9 +86,9 @@ use std::str::FromStr;
 use std::{fmt, iter};
 
 use md5::{Digest, Md5};
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{Hash64, Hash128, HashStable, StableHasher};
 use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc};
+use rustc_data_structures::unord::UnordMap;
 use sha1::Sha1;
 use sha2::Sha256;
 
@@ -103,7 +104,7 @@ pub struct SessionGlobals {
     span_interner: Lock<span_encoding::SpanInterner>,
     /// Maps a macro argument token into use of the corresponding metavariable in the macro body.
     /// Collisions are possible and processed in `maybe_use_metavar_location` on best effort basis.
-    metavar_spans: Lock<FxHashMap<Span, Span>>,
+    metavar_spans: MetavarSpansMap,
     hygiene_data: Lock<hygiene::HygieneData>,
 
     /// The session's source map, if there is one. This field should only be
@@ -177,9 +178,42 @@ pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R {
 // deserialization.
 scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals);
 
+#[derive(Default)]
+pub struct MetavarSpansMap(FreezeLock<UnordMap<Span, (Span, bool)>>);
+
+impl MetavarSpansMap {
+    pub fn insert(&self, span: Span, var_span: Span) -> bool {
+        match self.0.write().try_insert(span, (var_span, false)) {
+            Ok(_) => true,
+            Err(entry) => entry.entry.get().0 == var_span,
+        }
+    }
+
+    /// Read a span and record that it was read.
+    pub fn get(&self, span: Span) -> Option<Span> {
+        if let Some(mut mspans) = self.0.try_write() {
+            if let Some((var_span, read)) = mspans.get_mut(&span) {
+                *read = true;
+                Some(*var_span)
+            } else {
+                None
+            }
+        } else {
+            if let Some((span, true)) = self.0.read().get(&span) { Some(*span) } else { None }
+        }
+    }
+
+    /// Freeze the set, and return the spans which have been read.
+    ///
+    /// After this is frozen, no spans that have not been read can be read.
+    pub fn freeze_and_get_read_spans(&self) -> UnordMap<Span, Span> {
+        self.0.freeze().items().filter(|(_, (_, b))| *b).map(|(s1, (s2, _))| (*s1, *s2)).collect()
+    }
+}
+
 #[inline]
-pub fn with_metavar_spans<R>(f: impl FnOnce(&mut FxHashMap<Span, Span>) -> R) -> R {
-    with_session_globals(|session_globals| f(&mut session_globals.metavar_spans.lock()))
+pub fn with_metavar_spans<R>(f: impl FnOnce(&MetavarSpansMap) -> R) -> R {
+    with_session_globals(|session_globals| f(&session_globals.metavar_spans))
 }
 
 // FIXME: We should use this enum or something like it to get rid of the
@@ -305,8 +339,8 @@ impl RealFileName {
 #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, Decodable, Encodable)]
 pub enum FileName {
     Real(RealFileName),
-    /// Call to `quote!`.
-    QuoteExpansion(Hash64),
+    /// Strings provided as `--cfg [cfgspec]`.
+    CfgSpec(Hash64),
     /// Command line.
     Anon(Hash64),
     /// Hack in `src/librustc_ast/parse.rs`.
@@ -353,7 +387,7 @@ impl fmt::Display for FileNameDisplay<'_> {
             Real(ref name) => {
                 write!(fmt, "{}", name.to_string_lossy(self.display_pref))
             }
-            QuoteExpansion(_) => write!(fmt, "<quote expansion>"),
+            CfgSpec(_) => write!(fmt, "<cfgspec>"),
             MacroExpansion(_) => write!(fmt, "<macro expansion>"),
             Anon(_) => write!(fmt, "<anon>"),
             ProcMacroSourceCode(_) => write!(fmt, "<proc-macro source code>"),
@@ -384,7 +418,7 @@ impl FileName {
             | ProcMacroSourceCode(_)
             | CliCrateAttr(_)
             | Custom(_)
-            | QuoteExpansion(_)
+            | CfgSpec(_)
             | DocTest(_, _)
             | InlineAsm(_) => false,
         }
@@ -425,7 +459,7 @@ impl FileName {
     pub fn cfg_spec_source_code(src: &str) -> FileName {
         let mut hasher = StableHasher::new();
         src.hash(&mut hasher);
-        FileName::QuoteExpansion(hasher.finish())
+        FileName::CfgSpec(hasher.finish())
     }
 
     pub fn cli_crate_attr_source_code(src: &str) -> FileName {
@@ -872,8 +906,7 @@ impl Span {
 
     /// Check if you can select metavar spans for the given spans to get matching contexts.
     fn try_metavars(a: SpanData, b: SpanData, a_orig: Span, b_orig: Span) -> (SpanData, SpanData) {
-        let get = |mspans: &FxHashMap<_, _>, s| mspans.get(&s).copied();
-        match with_metavar_spans(|mspans| (get(mspans, a_orig), get(mspans, b_orig))) {
+        match with_metavar_spans(|mspans| (mspans.get(a_orig), mspans.get(b_orig))) {
             (None, None) => {}
             (Some(meta_a), None) => {
                 let meta_a = meta_a.data();
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index f5ce5dbc9d6..1fb15fe9800 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -707,7 +707,6 @@ symbols! {
         coverage,
         coverage_attribute,
         cr,
-        crate_id,
         crate_in_paths,
         crate_local,
         crate_name,
@@ -1189,6 +1188,7 @@ symbols! {
         link_section,
         linkage,
         linker,
+        linker_messages,
         lint_reasons,
         literal,
         load,
@@ -1389,7 +1389,6 @@ symbols! {
         no_mangle,
         no_sanitize,
         no_stack_check,
-        no_start,
         no_std,
         nomem,
         non_ascii_idents,
diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs
index 3a71592cbe0..92c1f6e7148 100644
--- a/compiler/rustc_target/src/callconv/powerpc64.rs
+++ b/compiler/rustc_target/src/callconv/powerpc64.rs
@@ -58,8 +58,10 @@ where
 
     // The AIX ABI expect byval for aggregates
     // See https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/Targets/PPC.cpp.
+    // The incoming parameter is represented as a pointer in the IR,
+    // the alignment is associated with the size of the register. (align 8 for 64bit)
     if !is_ret && abi == AIX {
-        arg.pass_by_stack_offset(None);
+        arg.pass_by_stack_offset(Some(Align::from_bytes(8).unwrap()));
         return;
     }
 
diff --git a/compiler/rustc_target/src/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs
index c99eb9226ef..a73c1a0f46c 100644
--- a/compiler/rustc_target/src/callconv/s390x.rs
+++ b/compiler/rustc_target/src/callconv/s390x.rs
@@ -38,9 +38,17 @@ where
     }
 
     let size = arg.layout.size;
-    if size.bits() <= 128 && arg.layout.is_single_vector_element(cx, size) {
-        arg.cast_to(Reg { kind: RegKind::Vector, size });
-        return;
+    if size.bits() <= 128 {
+        if let BackendRepr::Vector { .. } = arg.layout.backend_repr {
+            // pass non-wrapped vector types using `PassMode::Direct`
+            return;
+        }
+
+        if arg.layout.is_single_vector_element(cx, size) {
+            // pass non-transparant wrappers around a vector as `PassMode::Cast`
+            arg.cast_to(Reg { kind: RegKind::Vector, size });
+            return;
+        }
     }
     if !arg.layout.is_aggregate() && size.bits() <= 64 {
         arg.extend_integer_width_to(64);
diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs
index 0944bda2687..816564d2fed 100644
--- a/compiler/rustc_target/src/callconv/x86_win64.rs
+++ b/compiler/rustc_target/src/callconv/x86_win64.rs
@@ -1,4 +1,4 @@
-use rustc_abi::{BackendRepr, Float, Primitive};
+use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size};
 
 use crate::abi::call::{ArgAbi, FnAbi, Reg};
 use crate::spec::HasTargetSpec;
@@ -6,7 +6,7 @@ use crate::spec::HasTargetSpec;
 // Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing
 
 pub(crate) fn compute_abi_info<Ty>(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
-    let fixup = |a: &mut ArgAbi<'_, Ty>| {
+    let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| {
         match a.layout.backend_repr {
             BackendRepr::Uninhabited | BackendRepr::Memory { sized: false } => {}
             BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
@@ -23,11 +23,16 @@ pub(crate) fn compute_abi_info<Ty>(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<
                 // (probably what clang calls "illegal vectors").
             }
             BackendRepr::Scalar(scalar) => {
-                // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up
-                // with what LLVM expects.
-                if a.layout.size.bytes() > 8
+                if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) {
+                    // `i128` is returned in xmm0 by Clang and GCC
+                    // FIXME(#134288): This may change for the `-msvc` targets in the future.
+                    let reg = Reg { kind: RegKind::Vector, size: Size::from_bits(128) };
+                    a.cast_to(reg);
+                } else if a.layout.size.bytes() > 8
                     && !matches!(scalar.primitive(), Primitive::Float(Float::F128))
                 {
+                    // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up
+                    // with what LLVM expects.
                     a.make_indirect();
                 } else {
                     a.extend_integer_width_to(32);
@@ -37,8 +42,9 @@ pub(crate) fn compute_abi_info<Ty>(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<
     };
 
     if !fn_abi.ret.is_ignore() {
-        fixup(&mut fn_abi.ret);
+        fixup(&mut fn_abi.ret, true);
     }
+
     for arg in fn_abi.args.iter_mut() {
         if arg.is_ignore() && arg.layout.is_zst() {
             // Windows ABIs do not talk about ZST since such types do not exist in MSVC.
@@ -49,7 +55,7 @@ pub(crate) fn compute_abi_info<Ty>(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<
             arg.make_indirect_from_ignore();
             continue;
         }
-        fixup(arg);
+        fixup(arg, false);
     }
     // FIXME: We should likely also do something about ZST return types, similar to above.
     // However, that's non-trivial due to `()`.
diff --git a/compiler/rustc_target/src/spec/base/nto_qnx.rs b/compiler/rustc_target/src/spec/base/nto_qnx.rs
index 65475d068d7..819e68a0500 100644
--- a/compiler/rustc_target/src/spec/base/nto_qnx.rs
+++ b/compiler/rustc_target/src/spec/base/nto_qnx.rs
@@ -1,4 +1,6 @@
-use crate::spec::{RelroLevel, TargetOptions, cvs};
+use crate::spec::{
+    Cc, LinkArgs, LinkerFlavor, Lld, RelroLevel, Target, TargetMetadata, TargetOptions, cvs,
+};
 
 pub(crate) fn opts() -> TargetOptions {
     TargetOptions {
@@ -16,3 +18,96 @@ pub(crate) fn opts() -> TargetOptions {
         ..Default::default()
     }
 }
+
+pub(crate) fn meta() -> TargetMetadata {
+    TargetMetadata { description: None, tier: Some(3), host_tools: Some(false), std: Some(true) }
+}
+
+pub(crate) fn aarch64() -> Target {
+    Target {
+        llvm_target: "aarch64-unknown-unknown".into(),
+        metadata: meta(),
+        pointer_width: 64,
+        // from: https://llvm.org/docs/LangRef.html#data-layout
+        // e         = little endian
+        // m:e       = ELF mangling: Private symbols get a .L prefix
+        // i8:8:32   = 8-bit-integer, minimum_alignment=8, preferred_alignment=32
+        // i16:16:32 = 16-bit-integer, minimum_alignment=16, preferred_alignment=32
+        // i64:64    = 64-bit-integer, minimum_alignment=64, preferred_alignment=64
+        // i128:128  = 128-bit-integer, minimum_alignment=128, preferred_alignment=128
+        // n32:64    = 32 and 64 are native integer widths; Elements of this set are considered to support most general arithmetic operations efficiently.
+        // S128      = 128 bits are the natural alignment of the stack in bits.
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
+        arch: "aarch64".into(),
+        options: TargetOptions {
+            features: "+v8a".into(),
+            max_atomic_width: Some(128),
+            ..opts()
+        }
+    }
+}
+
+pub(crate) fn x86_64() -> Target {
+    Target {
+        llvm_target: "x86_64-pc-unknown".into(),
+        metadata: meta(),
+        pointer_width: 64,
+        data_layout:
+            "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
+        arch: "x86_64".into(),
+        options: TargetOptions {
+            cpu: "x86-64".into(),
+            plt_by_default: false,
+            max_atomic_width: Some(64),
+            vendor: "pc".into(),
+            ..opts()
+        },
+    }
+}
+
+pub(crate) fn pre_link_args(api_var: ApiVariant, arch: Arch) -> LinkArgs {
+    let (qcc_arg, arch_lib_dir) = match arch {
+        Arch::Aarch64 => ("-Vgcc_ntoaarch64le_cxx", "aarch64le"),
+        Arch::I586 => {
+            ("-Vgcc_ntox86_cxx", "notSupportedByQnx_compiler/rustc_target/src/spec/base/nto_qnx.rs")
+        }
+        Arch::X86_64 => ("-Vgcc_ntox86_64_cxx", "x86_64"),
+    };
+    match api_var {
+        ApiVariant::Default => {
+            TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[qcc_arg])
+        }
+        ApiVariant::IoSock => TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[
+            qcc_arg,
+            get_iosock_param(arch_lib_dir),
+        ]),
+    }
+}
+
+pub(crate) enum ApiVariant {
+    Default,
+    IoSock,
+}
+
+pub(crate) enum Arch {
+    Aarch64,
+    I586,
+    X86_64,
+}
+
+// When using `io-sock` on QNX, we must add a search path for the linker so
+// that it prefers the io-sock version.
+// The path depends on the host, i.e. we cannot hard-code it here, but have
+// to determine it when the compiler runs.
+// When using the QNX toolchain, the environment variable QNX_TARGET is always set.
+// More information:
+// https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.io_sock/topic/migrate_app.html
+fn get_iosock_param(arch_lib_dir: &str) -> &'static str {
+    let target_dir = std::env::var("QNX_TARGET")
+        .unwrap_or_else(|_| "QNX_TARGET_not_set_please_source_qnxsdp-env.sh".into());
+    let linker_param = format!("-L{target_dir}/{arch_lib_dir}/io-sock/lib");
+
+    // FIXME: leaking this is kind of weird: we're feeding these into something that expects an
+    // `AsRef<OsStr>`, but often converts to `OsString` anyways, so shouldn't we just demand an `OsString`?
+    linker_param.leak()
+}
diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs
index e975102e238..d8b6ae8cf32 100644
--- a/compiler/rustc_target/src/spec/base/windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs
@@ -97,9 +97,9 @@ pub(crate) fn opts() -> TargetOptions {
         emit_debug_gdb_scripts: false,
         requires_uwtable: true,
         eh_frame_header: false,
+        debuginfo_kind: DebuginfoKind::Dwarf,
         // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to
         // output DWO, despite using DWARF, doesn't use ELF..
-        debuginfo_kind: DebuginfoKind::Pdb,
         supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
         ..Default::default()
     }
diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs
index 4f370ec8bd0..86e52117dbf 100644
--- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs
+++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs
@@ -44,9 +44,9 @@ pub(crate) fn opts() -> TargetOptions {
         has_thread_local: true,
         crt_static_allows_dylibs: true,
         crt_static_respected: true,
+        debuginfo_kind: DebuginfoKind::Dwarf,
         // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to
         // output DWO, despite using DWARF, doesn't use ELF..
-        debuginfo_kind: DebuginfoKind::Pdb,
         supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
         ..Default::default()
     }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 1f2df7f0168..bcd2aff54bb 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1853,6 +1853,8 @@ supported_targets! {
 
     ("armv7a-none-eabi", armv7a_none_eabi),
     ("armv7a-none-eabihf", armv7a_none_eabihf),
+    ("armv7a-nuttx-eabi", armv7a_nuttx_eabi),
+    ("armv7a-nuttx-eabihf", armv7a_nuttx_eabihf),
 
     ("msp430-none-elf", msp430_none_elf),
 
@@ -1896,6 +1898,7 @@ supported_targets! {
 
     ("aarch64-unknown-none", aarch64_unknown_none),
     ("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat),
+    ("aarch64-unknown-nuttx", aarch64_unknown_nuttx),
 
     ("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx),
 
@@ -1960,7 +1963,11 @@ supported_targets! {
 
     ("aarch64-unknown-nto-qnx700", aarch64_unknown_nto_qnx700),
     ("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx710),
+    ("aarch64-unknown-nto-qnx710_iosock", aarch64_unknown_nto_qnx710_iosock),
+    ("aarch64-unknown-nto-qnx800", aarch64_unknown_nto_qnx800),
     ("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710),
+    ("x86_64-pc-nto-qnx710_iosock", x86_64_pc_nto_qnx710_iosock),
+    ("x86_64-pc-nto-qnx800", x86_64_pc_nto_qnx800),
     ("i586-pc-nto-qnx700", i586_pc_nto_qnx700),
 
     ("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos),
@@ -1971,6 +1978,8 @@ supported_targets! {
     ("x86_64-unknown-linux-none", x86_64_unknown_linux_none),
 
     ("thumbv6m-nuttx-eabi", thumbv6m_nuttx_eabi),
+    ("thumbv7a-nuttx-eabi", thumbv7a_nuttx_eabi),
+    ("thumbv7a-nuttx-eabihf", thumbv7a_nuttx_eabihf),
     ("thumbv7m-nuttx-eabi", thumbv7m_nuttx_eabi),
     ("thumbv7em-nuttx-eabi", thumbv7em_nuttx_eabi),
     ("thumbv7em-nuttx-eabihf", thumbv7em_nuttx_eabihf),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs
index d6b77ffd091..3b719ebaf07 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs
@@ -7,7 +7,8 @@
 // For example, `-C target-cpu=cortex-a53`.
 
 use crate::spec::{
-    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, StackProbeType, Target, TargetOptions,
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target,
+    TargetOptions,
 };
 
 pub(crate) fn target() -> Target {
@@ -19,6 +20,7 @@ pub(crate) fn target() -> Target {
         relocation_model: RelocModel::Static,
         disable_redzone: true,
         max_atomic_width: Some(128),
+        supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
         stack_probes: StackProbeType::Inline,
         panic_strategy: PanicStrategy::Abort,
         ..Default::default()
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx700.rs
index 441ed7cf153..b26e6f19e1a 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx700.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx700.rs
@@ -1,37 +1,11 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions, base};
+use crate::spec::Target;
+use crate::spec::base::nto_qnx;
 
 pub(crate) fn target() -> Target {
-    // In QNX, libc does not provide a compatible ABI between versions.
-    // To distinguish between QNX versions, we needed a stable conditional compilation switch,
-    // which is why we needed to implement different targets in the compiler.
-    Target {
-        llvm_target: "aarch64-unknown-unknown".into(),
-        metadata: crate::spec::TargetMetadata {
-            description: Some("ARM64 QNX Neutrino 7.0 RTOS".into()),
-            tier: Some(3),
-            host_tools: Some(false),
-            std: Some(true),
-        },
-        pointer_width: 64,
-        // from: https://llvm.org/docs/LangRef.html#data-layout
-        // e         = little endian
-        // m:e       = ELF mangling: Private symbols get a .L prefix
-        // i8:8:32   = 8-bit-integer, minimum_alignment=8, preferred_alignment=32
-        // i16:16:32 = 16-bit-integer, minimum_alignment=16, preferred_alignment=32
-        // i64:64    = 64-bit-integer, minimum_alignment=64, preferred_alignment=64
-        // i128:128  = 128-bit-integer, minimum_alignment=128, preferred_alignment=128
-        // n32:64    = 32 and 64 are native integer widths; Elements of this set are considered to support most general arithmetic operations efficiently.
-        // S128      = 128 bits are the natural alignment of the stack in bits.
-        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
-        arch: "aarch64".into(),
-        options: TargetOptions {
-            features: "+v8a".into(),
-            max_atomic_width: Some(128),
-            pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[
-                "-Vgcc_ntoaarch64le_cxx",
-            ]),
-            env: "nto70".into(),
-            ..base::nto_qnx::opts()
-        },
-    }
+    let mut target = nto_qnx::aarch64();
+    target.metadata.description = Some("ARM64 QNX Neutrino 7.0 RTOS".into());
+    target.options.pre_link_args =
+        nto_qnx::pre_link_args(nto_qnx::ApiVariant::Default, nto_qnx::Arch::Aarch64);
+    target.options.env = "nto70".into();
+    target
 }
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs
index 5b5a21fca95..3a78952c36c 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs
@@ -1,8 +1,12 @@
 use crate::spec::Target;
+use crate::spec::base::nto_qnx;
 
 pub(crate) fn target() -> Target {
-    let mut base = super::aarch64_unknown_nto_qnx700::target();
-    base.metadata.description = Some("ARM64 QNX Neutrino 7.1 RTOS".into());
-    base.options.env = "nto71".into();
-    base
+    let mut target = nto_qnx::aarch64();
+    target.metadata.description =
+        Some("ARM64 QNX Neutrino 7.1 RTOS with io-pkt network stack".into());
+    target.options.pre_link_args =
+        nto_qnx::pre_link_args(nto_qnx::ApiVariant::Default, nto_qnx::Arch::Aarch64);
+    target.options.env = "nto71".into();
+    target
 }
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs
new file mode 100644
index 00000000000..4964f4078f5
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs
@@ -0,0 +1,12 @@
+use crate::spec::Target;
+use crate::spec::base::nto_qnx;
+
+pub(crate) fn target() -> Target {
+    let mut target = nto_qnx::aarch64();
+    target.metadata.description =
+        Some("ARM64 QNX Neutrino 7.1 RTOS with io-sock network stack".into());
+    target.options.pre_link_args =
+        nto_qnx::pre_link_args(nto_qnx::ApiVariant::IoSock, nto_qnx::Arch::Aarch64);
+    target.options.env = "nto71_iosock".into();
+    target
+}
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx800.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx800.rs
new file mode 100644
index 00000000000..5b820681efe
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx800.rs
@@ -0,0 +1,11 @@
+use crate::spec::Target;
+use crate::spec::base::nto_qnx;
+
+pub(crate) fn target() -> Target {
+    let mut target = nto_qnx::aarch64();
+    target.metadata.description = Some("ARM64 QNX Neutrino 8.0 RTOS".into());
+    target.options.pre_link_args =
+        nto_qnx::pre_link_args(nto_qnx::ApiVariant::Default, nto_qnx::Arch::Aarch64);
+    target.options.env = "nto80".into();
+    target
+}
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs
new file mode 100644
index 00000000000..582211b02b6
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs
@@ -0,0 +1,46 @@
+// Generic AArch64 target for NuttX OS
+//
+// Can be used in conjunction with the `target-feature` and
+// `target-cpu` compiler flags to opt-in more hardware-specific
+// features.
+//
+// For example, `-C target-cpu=cortex-a53`.
+
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target,
+    TargetOptions, cvs,
+};
+
+pub(crate) fn target() -> Target {
+    let opts = TargetOptions {
+        linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+        linker: Some("rust-lld".into()),
+        // Enable the Cortex-A53 errata 843419 mitigation by default
+        pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), &[
+            "--fix-cortex-a53-843419",
+        ]),
+        features: "+v8a,+strict-align,+neon,+fp-armv8".into(),
+        supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
+        relocation_model: RelocModel::Static,
+        disable_redzone: true,
+        max_atomic_width: Some(128),
+        stack_probes: StackProbeType::Inline,
+        panic_strategy: PanicStrategy::Abort,
+        families: cvs!["unix"],
+        os: "nuttx".into(),
+        ..Default::default()
+    };
+    Target {
+        llvm_target: "aarch64-unknown-none".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("AArch64 NuttX".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
+        },
+        pointer_width: 64,
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
+        arch: "aarch64".into(),
+        options: opts,
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs
new file mode 100644
index 00000000000..08cbfc74396
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs
@@ -0,0 +1,41 @@
+// Targets Cortex-A7/A8/A9 processors (ARMv7-A) running NuttX
+//
+// This target assumes that the device does NOT have a FPU (Floating Point Unit)
+// and will use software floating point operations. This matches the NuttX EABI
+// configuration without hardware floating point support.
+
+use crate::spec::{
+    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs,
+};
+
+pub(crate) fn target() -> Target {
+    let opts = TargetOptions {
+        abi: "eabi".into(),
+        llvm_floatabi: Some(FloatAbi::Soft),
+        linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+        linker: Some("rust-lld".into()),
+        features: "+v7,+thumb2,+soft-float,-neon,+strict-align".into(),
+        relocation_model: RelocModel::Static,
+        disable_redzone: true,
+        max_atomic_width: Some(64),
+        panic_strategy: PanicStrategy::Abort,
+        emit_debug_gdb_scripts: false,
+        c_enum_min_bits: Some(8),
+        families: cvs!["unix"],
+        os: "nuttx".into(),
+        ..Default::default()
+    };
+    Target {
+        llvm_target: "armv7a-none-eabi".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("ARMv7-A Cortex-A with NuttX".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
+        },
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+        arch: "arm".into(),
+        options: opts,
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs
new file mode 100644
index 00000000000..f68c11a9c68
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs
@@ -0,0 +1,41 @@
+// Targets Cortex-A7/A8/A9 processors (ARMv7-A) running NuttX with hardware floating point
+//
+// This target assumes that the device has a FPU (Floating Point Unit)
+// and will use hardware floating point operations. This matches the NuttX EABI
+// configuration with hardware floating point support.
+
+use crate::spec::{
+    Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs,
+};
+
+pub(crate) fn target() -> Target {
+    let opts = TargetOptions {
+        abi: "eabihf".into(),
+        llvm_floatabi: Some(FloatAbi::Hard),
+        linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+        linker: Some("rust-lld".into()),
+        features: "+v7,+thumb2,+vfp3,+neon,+strict-align".into(),
+        relocation_model: RelocModel::Static,
+        disable_redzone: true,
+        max_atomic_width: Some(64),
+        panic_strategy: PanicStrategy::Abort,
+        emit_debug_gdb_scripts: false,
+        c_enum_min_bits: Some(8),
+        families: cvs!["unix"],
+        os: "nuttx".into(),
+        ..Default::default()
+    };
+    Target {
+        llvm_target: "armv7a-none-eabihf".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("ARMv7-A Cortex-A with NuttX (hard float)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
+        },
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+        arch: "arm".into(),
+        options: opts,
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs
index 7648f81fd4d..fa21cfbab8a 100644
--- a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs
+++ b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs
@@ -1,14 +1,13 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base};
+use crate::spec::base::nto_qnx;
+use crate::spec::{StackProbeType, Target, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
+    let mut meta = nto_qnx::meta();
+    meta.description = Some("32-bit x86 QNX Neutrino 7.0 RTOS".into());
+    meta.std = Some(false);
     Target {
         llvm_target: "i586-pc-unknown".into(),
-        metadata: crate::spec::TargetMetadata {
-            description: Some("32-bit x86 QNX Neutrino 7.0 RTOS".into()),
-            tier: Some(3),
-            host_tools: Some(false),
-            std: Some(false),
-        },
+        metadata: meta,
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             i128:128-f64:32:64-f80:32-n8:16:32-S128"
@@ -17,9 +16,10 @@ pub(crate) fn target() -> Target {
         options: TargetOptions {
             cpu: "pentium4".into(),
             max_atomic_width: Some(64),
-            pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[
-                "-Vgcc_ntox86_cxx",
-            ]),
+            pre_link_args: nto_qnx::pre_link_args(
+                nto_qnx::ApiVariant::Default,
+                nto_qnx::Arch::I586,
+            ),
             env: "nto70".into(),
             vendor: "pc".into(),
             stack_probes: StackProbeType::Inline,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs
index b1f52973c10..771ffac7d80 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs
@@ -1,6 +1,7 @@
 use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
 
 pub(crate) fn target() -> Target {
+    let abi = "ilp32e";
     Target {
         // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also
         // `options.llvm_abiname`.
@@ -16,11 +17,12 @@ pub(crate) fn target() -> Target {
         arch: "riscv32".into(),
 
         options: TargetOptions {
+            abi: abi.into(),
             linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
             linker: Some("rust-lld".into()),
             cpu: "generic-rv32".into(),
             // The ilp32e ABI specifies the `data_layout`
-            llvm_abiname: "ilp32e".into(),
+            llvm_abiname: abi.into(),
             max_atomic_width: Some(32),
             atomic_cas: false,
             features: "+e,+forced-atomics".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs
index feeaa48778d..3b81c278d3a 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs
@@ -1,6 +1,7 @@
 use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
 
 pub(crate) fn target() -> Target {
+    let abi = "ilp32e";
     Target {
         // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also
         // `options.llvm_abiname`.
@@ -16,11 +17,12 @@ pub(crate) fn target() -> Target {
         arch: "riscv32".into(),
 
         options: TargetOptions {
+            abi: abi.into(),
             linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
             linker: Some("rust-lld".into()),
             cpu: "generic-rv32".into(),
             // The ilp32e ABI specifies the `data_layout`
-            llvm_abiname: "ilp32e".into(),
+            llvm_abiname: abi.into(),
             max_atomic_width: Some(32),
             atomic_cas: false,
             features: "+e,+m,+forced-atomics".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs
index 45d73c13233..c18b51ad46e 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs
@@ -1,6 +1,7 @@
 use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
 
 pub(crate) fn target() -> Target {
+    let abi = "ilp32e";
     Target {
         // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also
         // `options.llvm_abiname`.
@@ -16,11 +17,12 @@ pub(crate) fn target() -> Target {
         arch: "riscv32".into(),
 
         options: TargetOptions {
+            abi: abi.into(),
             linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
             linker: Some("rust-lld".into()),
             cpu: "generic-rv32".into(),
             // The ilp32e ABI specifies the `data_layout`
-            llvm_abiname: "ilp32e".into(),
+            llvm_abiname: abi.into(),
             max_atomic_width: Some(32),
             atomic_cas: false,
             features: "+e,+m,+c,+forced-atomics".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs
index 31c9180c509..3eb3d18faf4 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs
@@ -6,9 +6,9 @@ pub(crate) fn target() -> Target {
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
+            tier: Some(3),
             host_tools: None,
-            std: None,
+            std: Some(true),
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs
index 08dd3cc2a09..7864f7f8f9a 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs
@@ -6,9 +6,9 @@ pub(crate) fn target() -> Target {
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
+            tier: Some(3),
             host_tools: None,
-            std: None,
+            std: Some(true),
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs
index e86549806dd..60d8ec576af 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs
@@ -6,9 +6,9 @@ pub(crate) fn target() -> Target {
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
+            tier: Some(3),
             host_tools: None,
-            std: None,
+            std: Some(true),
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs
index c389759aecd..2cbb8c19b84 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs
@@ -8,9 +8,9 @@ pub(crate) fn target() -> Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
+            tier: Some(3),
             host_tools: None,
-            std: None,
+            std: Some(true),
         },
         llvm_target: "riscv64".into(),
         pointer_width: 64,
diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
index 9c181665581..306b23d2787 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
@@ -8,9 +8,9 @@ pub(crate) fn target() -> Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
+            tier: Some(3),
             host_tools: None,
-            std: None,
+            std: Some(true),
         },
         llvm_target: "riscv64".into(),
         pointer_width: 64,
diff --git a/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs
index 5799bbf551f..dcf98acc41f 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs
@@ -7,9 +7,9 @@ pub(crate) fn target() -> Target {
         llvm_target: "thumbv6m-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
+            tier: Some(3),
             host_tools: None,
-            std: None,
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
@@ -22,12 +22,9 @@ pub(crate) fn target() -> Target {
             llvm_floatabi: Some(FloatAbi::Soft),
             // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them
             // with +strict-align.
-            // Also force-enable 32-bit atomics, which allows the use of atomic load/store only.
-            // The resulting atomics are ABI incompatible with atomics backed by libatomic.
-            features: "+strict-align,+atomics-32".into(),
-            // There are no atomic CAS instructions available in the instruction set of the ARMv6-M
-            // architecture
-            atomic_cas: false,
+            // The ARMv6-M doesn't support hardware atomic operations, use atomic builtins instead.
+            features: "+strict-align".into(),
+            max_atomic_width: Some(32),
             ..base::thumb::opts()
         },
     }
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs
new file mode 100644
index 00000000000..b5cb393f4b0
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs
@@ -0,0 +1,33 @@
+// Targets Cortex-A7/A8/A9 processors (ARMv7-A)
+//
+// This target assumes that the device does NOT have a FPU (Floating Point Unit)
+// and will use software floating point operations. This matches the NuttX EABI
+// configuration without hardware floating point support.
+
+use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs};
+
+pub(crate) fn target() -> Target {
+    Target {
+        llvm_target: "thumbv7a-none-eabi".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: None,
+            tier: Some(3),
+            host_tools: None,
+            std: Some(true),
+        },
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+        arch: "arm".into(),
+
+        options: TargetOptions {
+            families: cvs!["unix"],
+            os: "nuttx".into(),
+            abi: "eabi".into(),
+            llvm_floatabi: Some(FloatAbi::Soft),
+            // Cortex-A7/A8/A9 with software floating point
+            features: "+soft-float,-neon".into(),
+            max_atomic_width: Some(64),
+            ..base::thumb::opts()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs
new file mode 100644
index 00000000000..1aa44a8cc93
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs
@@ -0,0 +1,37 @@
+// Targets Cortex-A7/A8/A9 processors (ARMv7-A)
+//
+// This target assumes that the device has a FPU (Floating Point Unit) and lowers all (single
+// precision) floating point operations to hardware instructions. Cortex-A7/A8/A9 processors
+// support VFPv3-D32 or VFPv4-D32 floating point units with optional double-precision support.
+//
+// This target uses the "hard" floating convention (ABI) where floating point values
+// are passed to/from subroutines via FPU registers (S0, S1, D0, D1, etc.).
+
+use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs};
+
+pub(crate) fn target() -> Target {
+    Target {
+        llvm_target: "thumbv7a-none-eabihf".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: None,
+            tier: Some(3),
+            host_tools: None,
+            std: Some(true),
+        },
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+        arch: "arm".into(),
+
+        options: TargetOptions {
+            families: cvs!["unix"],
+            os: "nuttx".into(),
+            abi: "eabihf".into(),
+            llvm_floatabi: Some(FloatAbi::Hard),
+            // Cortex-A7/A8/A9 support VFPv3-D32/VFPv4-D32 with optional double-precision
+            // and NEON SIMD instructions
+            features: "+vfp3,+neon".into(),
+            max_atomic_width: Some(64),
+            ..base::thumb::opts()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs
index 536d128590f..a3bc4013e53 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs
@@ -16,9 +16,9 @@ pub(crate) fn target() -> Target {
         llvm_target: "thumbv7em-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
+            tier: Some(3),
             host_tools: None,
-            std: None,
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs
index 35e92b81d87..14bbe38257d 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs
@@ -15,9 +15,9 @@ pub(crate) fn target() -> Target {
         llvm_target: "thumbv7em-none-eabihf".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
+            tier: Some(3),
             host_tools: None,
-            std: None,
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs
index 320867444ad..2a77f48a9cd 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs
@@ -7,9 +7,9 @@ pub(crate) fn target() -> Target {
         llvm_target: "thumbv7m-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
+            tier: Some(3),
             host_tools: None,
-            std: None,
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs
index 1af01b97666..25a100e9c7e 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs
@@ -7,9 +7,9 @@ pub(crate) fn target() -> Target {
         llvm_target: "thumbv8m.base-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
+            tier: Some(3),
             host_tools: None,
-            std: None,
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs
index 661d74217ad..0bfe2b32ad4 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs
@@ -8,9 +8,9 @@ pub(crate) fn target() -> Target {
         llvm_target: "thumbv8m.main-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
+            tier: Some(3),
             host_tools: None,
-            std: None,
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs
index 484d35bfc20..9f75f23aa93 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs
@@ -8,9 +8,9 @@ pub(crate) fn target() -> Target {
         llvm_target: "thumbv8m.main-none-eabihf".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
+            tier: Some(3),
             host_tools: None,
-            std: None,
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs
index 245a5f06765..248aa91862c 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs
@@ -1,28 +1,12 @@
-use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions, base};
+use crate::spec::Target;
+use crate::spec::base::nto_qnx;
 
 pub(crate) fn target() -> Target {
-    Target {
-        llvm_target: "x86_64-pc-unknown".into(),
-        metadata: crate::spec::TargetMetadata {
-            description: Some("x86 64-bit QNX Neutrino 7.1 RTOS".into()),
-            tier: Some(3),
-            host_tools: Some(false),
-            std: Some(true),
-        },
-        pointer_width: 64,
-        data_layout:
-            "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
-        arch: "x86_64".into(),
-        options: TargetOptions {
-            cpu: "x86-64".into(),
-            plt_by_default: false,
-            max_atomic_width: Some(64),
-            pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[
-                "-Vgcc_ntox86_64_cxx",
-            ]),
-            env: "nto71".into(),
-            vendor: "pc".into(),
-            ..base::nto_qnx::opts()
-        },
-    }
+    let mut target = nto_qnx::x86_64();
+    target.metadata.description =
+        Some("x86 64-bit QNX Neutrino 7.1 RTOS with io-pkt network stack".into());
+    target.options.pre_link_args =
+        nto_qnx::pre_link_args(nto_qnx::ApiVariant::Default, nto_qnx::Arch::X86_64);
+    target.options.env = "nto71".into();
+    target
 }
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs
new file mode 100644
index 00000000000..8f4c4924a29
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs
@@ -0,0 +1,12 @@
+use crate::spec::Target;
+use crate::spec::base::nto_qnx;
+
+pub(crate) fn target() -> Target {
+    let mut target = nto_qnx::x86_64();
+    target.metadata.description =
+        Some("x86 64-bit QNX Neutrino 7.1 RTOS with io-sock network stack".into());
+    target.options.pre_link_args =
+        nto_qnx::pre_link_args(nto_qnx::ApiVariant::IoSock, nto_qnx::Arch::X86_64);
+    target.options.env = "nto71_iosock".into();
+    target
+}
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx800.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx800.rs
new file mode 100644
index 00000000000..d91a94a2ba5
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx800.rs
@@ -0,0 +1,11 @@
+use crate::spec::Target;
+use crate::spec::base::nto_qnx;
+
+pub(crate) fn target() -> Target {
+    let mut target = nto_qnx::x86_64();
+    target.metadata.description = Some("x86 64-bit QNX Neutrino 8.0 RTOS".into());
+    target.options.pre_link_args =
+        nto_qnx::pre_link_args(nto_qnx::ApiVariant::Default, nto_qnx::Arch::X86_64);
+    target.options.env = "nto80".into();
+    target
+}
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index b82bb27eb79..750d2756b4a 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -261,7 +261,6 @@ trait_selection_oc_fn_lang_correct_type = {$lang_item_name ->
         *[lang_item_name] lang item `{$lang_item_name}`
     } function has wrong type
 trait_selection_oc_fn_main_correct_type = `main` function has wrong type
-trait_selection_oc_fn_start_correct_type = `#[start]` function has wrong type
 trait_selection_oc_generic = mismatched types
 
 trait_selection_oc_if_else_different = `if` and `else` have incompatible types
@@ -396,7 +395,6 @@ trait_selection_subtype = ...so that the {$requirement ->
     [if_else_different] `if` and `else` have incompatible types
     [no_else] `if` missing an `else` returns `()`
     [fn_main_correct_type] `main` function has the correct type
-    [fn_start_correct_type] `#[start]` function has the correct type
     [fn_lang_correct_type] lang item function has the correct type
     [intrinsic_correct_type] intrinsic has the correct type
     [method_correct_type] method receiver has the correct type
@@ -410,7 +408,6 @@ trait_selection_subtype_2 = ...so that {$requirement ->
     [if_else_different] `if` and `else` have incompatible types
     [no_else] `if` missing an `else` returns `()`
     [fn_main_correct_type] `main` function has the correct type
-    [fn_start_correct_type] `#[start]` function has the correct type
     [fn_lang_correct_type] lang item function has the correct type
     [intrinsic_correct_type] intrinsic has the correct type
     [method_correct_type] method receiver has the correct type
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 9778299eb19..bcb6ac13b8f 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -435,6 +435,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
         terr: TypeError<'tcx>,
         param_env: Option<ParamEnv<'tcx>>,
+        path: &mut Option<PathBuf>,
     ) {
         match *cause.code() {
             ObligationCauseCode::Pattern {
@@ -457,6 +458,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             format!("this is an iterator with items of type `{}`", args.type_at(0)),
                         );
                     } else {
+                        let expected_ty = self.tcx.short_ty_string(expected_ty, path);
                         err.span_label(span, format!("this expression has type `{expected_ty}`"));
                     }
                 }
@@ -717,53 +719,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         value: &mut DiagStyledString,
         other_value: &mut DiagStyledString,
         name: String,
-        sub: ty::GenericArgsRef<'tcx>,
+        args: &[ty::GenericArg<'tcx>],
         pos: usize,
         other_ty: Ty<'tcx>,
     ) {
         // `value` and `other_value` hold two incomplete type representation for display.
         // `name` is the path of both types being compared. `sub`
         value.push_highlighted(name);
-        let len = sub.len();
-        if len > 0 {
-            value.push_highlighted("<");
-        }
 
-        // Output the lifetimes for the first type
-        let lifetimes = sub
-            .regions()
-            .map(|lifetime| {
-                let s = lifetime.to_string();
-                if s.is_empty() { "'_".to_string() } else { s }
-            })
-            .collect::<Vec<_>>()
-            .join(", ");
-        if !lifetimes.is_empty() {
-            if sub.regions().count() < len {
-                value.push_normal(lifetimes + ", ");
-            } else {
-                value.push_normal(lifetimes);
-            }
+        if args.is_empty() {
+            return;
         }
+        value.push_highlighted("<");
 
-        // Highlight all the type arguments that aren't at `pos` and compare the type argument at
-        // `pos` and `other_ty`.
-        for (i, type_arg) in sub.types().enumerate() {
-            if i == pos {
-                let values = self.cmp(type_arg, other_ty);
-                value.0.extend((values.0).0);
-                other_value.0.extend((values.1).0);
-            } else {
-                value.push_highlighted(type_arg.to_string());
+        for (i, arg) in args.iter().enumerate() {
+            if i > 0 {
+                value.push_normal(", ");
             }
 
-            if len > 0 && i != len - 1 {
-                value.push_normal(", ");
+            match arg.unpack() {
+                ty::GenericArgKind::Lifetime(lt) => {
+                    let s = lt.to_string();
+                    value.push_normal(if s.is_empty() { "'_" } else { &s });
+                }
+                ty::GenericArgKind::Const(ct) => {
+                    value.push_normal(ct.to_string());
+                }
+                // Highlight all the type arguments that aren't at `pos` and compare
+                // the type argument at `pos` and `other_ty`.
+                ty::GenericArgKind::Type(type_arg) => {
+                    if i == pos {
+                        let values = self.cmp(type_arg, other_ty);
+                        value.0.extend((values.0).0);
+                        other_value.0.extend((values.1).0);
+                    } else {
+                        value.push_highlighted(type_arg.to_string());
+                    }
+                }
             }
         }
-        if len > 0 {
-            value.push_highlighted(">");
-        }
+
+        value.push_highlighted(">");
     }
 
     /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`,
@@ -791,27 +787,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         t1_out: &mut DiagStyledString,
         t2_out: &mut DiagStyledString,
         path: String,
-        sub: &'tcx [ty::GenericArg<'tcx>],
+        args: &'tcx [ty::GenericArg<'tcx>],
         other_path: String,
         other_ty: Ty<'tcx>,
-    ) -> Option<()> {
-        // FIXME/HACK: Go back to `GenericArgsRef` to use its inherent methods,
-        // ideally that shouldn't be necessary.
-        let sub = self.tcx.mk_args(sub);
-        for (i, ta) in sub.types().enumerate() {
-            if ta == other_ty {
-                self.highlight_outer(t1_out, t2_out, path, sub, i, other_ty);
-                return Some(());
-            }
-            if let ty::Adt(def, _) = ta.kind() {
-                let path_ = self.tcx.def_path_str(def.did());
-                if path_ == other_path {
-                    self.highlight_outer(t1_out, t2_out, path, sub, i, other_ty);
-                    return Some(());
+    ) -> bool {
+        for (i, arg) in args.iter().enumerate() {
+            if let Some(ta) = arg.as_type() {
+                if ta == other_ty {
+                    self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
+                    return true;
+                }
+                if let ty::Adt(def, _) = ta.kind() {
+                    let path_ = self.tcx.def_path_str(def.did());
+                    if path_ == other_path {
+                        self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
+                        return true;
+                    }
                 }
             }
         }
-        None
+        false
     }
 
     /// Adds a `,` to the type representation only if it is appropriate.
@@ -819,10 +814,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         &self,
         value: &mut DiagStyledString,
         other_value: &mut DiagStyledString,
-        len: usize,
         pos: usize,
     ) {
-        if len > 0 && pos != len - 1 {
+        if pos > 0 {
             value.push_normal(", ");
             other_value.push_normal(", ");
         }
@@ -899,10 +893,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let len2 = sig2.inputs().len();
         if len1 == len2 {
             for (i, (l, r)) in iter::zip(sig1.inputs(), sig2.inputs()).enumerate() {
+                self.push_comma(&mut values.0, &mut values.1, i);
                 let (x1, x2) = self.cmp(*l, *r);
                 (values.0).0.extend(x1.0);
                 (values.1).0.extend(x2.0);
-                self.push_comma(&mut values.0, &mut values.1, len1, i);
             }
         } else {
             for (i, l) in sig1.inputs().iter().enumerate() {
@@ -1150,14 +1144,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     let len1 = sub_no_defaults_1.len();
                     let len2 = sub_no_defaults_2.len();
                     let common_len = cmp::min(len1, len2);
-                    let remainder1: Vec<_> = sub1.types().skip(common_len).collect();
-                    let remainder2: Vec<_> = sub2.types().skip(common_len).collect();
+                    let remainder1 = &sub1[common_len..];
+                    let remainder2 = &sub2[common_len..];
                     let common_default_params =
                         iter::zip(remainder1.iter().rev(), remainder2.iter().rev())
                             .filter(|(a, b)| a == b)
                             .count();
                     let len = sub1.len() - common_default_params;
-                    let consts_offset = len - sub1.consts().count();
 
                     // Only draw `<...>` if there are lifetime/type arguments.
                     if len > 0 {
@@ -1169,70 +1162,68 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         let s = lifetime.to_string();
                         if s.is_empty() { "'_".to_string() } else { s }
                     }
-                    // At one point we'd like to elide all lifetimes here, they are irrelevant for
-                    // all diagnostics that use this output
-                    //
-                    //     Foo<'x, '_, Bar>
-                    //     Foo<'y, '_, Qux>
-                    //         ^^  ^^  --- type arguments are not elided
-                    //         |   |
-                    //         |   elided as they were the same
-                    //         not elided, they were different, but irrelevant
-                    //
-                    // For bound lifetimes, keep the names of the lifetimes,
-                    // even if they are the same so that it's clear what's happening
-                    // if we have something like
-                    //
-                    // for<'r, 's> fn(Inv<'r>, Inv<'s>)
-                    // for<'r> fn(Inv<'r>, Inv<'r>)
-                    let lifetimes = sub1.regions().zip(sub2.regions());
-                    for (i, lifetimes) in lifetimes.enumerate() {
-                        let l1 = lifetime_display(lifetimes.0);
-                        let l2 = lifetime_display(lifetimes.1);
-                        if lifetimes.0 != lifetimes.1 {
-                            values.0.push_highlighted(l1);
-                            values.1.push_highlighted(l2);
-                        } else if lifetimes.0.is_bound() || self.tcx.sess.opts.verbose {
-                            values.0.push_normal(l1);
-                            values.1.push_normal(l2);
-                        } else {
-                            values.0.push_normal("'_");
-                            values.1.push_normal("'_");
-                        }
-                        self.push_comma(&mut values.0, &mut values.1, len, i);
-                    }
 
-                    // We're comparing two types with the same path, so we compare the type
-                    // arguments for both. If they are the same, do not highlight and elide from the
-                    // output.
-                    //     Foo<_, Bar>
-                    //     Foo<_, Qux>
-                    //         ^ elided type as this type argument was the same in both sides
-                    let type_arguments = sub1.types().zip(sub2.types());
-                    let regions_len = sub1.regions().count();
-                    let num_display_types = consts_offset - regions_len;
-                    for (i, (ta1, ta2)) in type_arguments.take(num_display_types).enumerate() {
-                        let i = i + regions_len;
-                        if ta1 == ta2 && !self.tcx.sess.opts.verbose {
-                            values.0.push_normal("_");
-                            values.1.push_normal("_");
-                        } else {
-                            recurse(ta1, ta2, &mut values);
+                    for (i, (arg1, arg2)) in sub1.iter().zip(sub2).enumerate().take(len) {
+                        self.push_comma(&mut values.0, &mut values.1, i);
+                        match arg1.unpack() {
+                            // At one point we'd like to elide all lifetimes here, they are
+                            // irrelevant for all diagnostics that use this output.
+                            //
+                            //     Foo<'x, '_, Bar>
+                            //     Foo<'y, '_, Qux>
+                            //         ^^  ^^  --- type arguments are not elided
+                            //         |   |
+                            //         |   elided as they were the same
+                            //         not elided, they were different, but irrelevant
+                            //
+                            // For bound lifetimes, keep the names of the lifetimes,
+                            // even if they are the same so that it's clear what's happening
+                            // if we have something like
+                            //
+                            // for<'r, 's> fn(Inv<'r>, Inv<'s>)
+                            // for<'r> fn(Inv<'r>, Inv<'r>)
+                            ty::GenericArgKind::Lifetime(l1) => {
+                                let l1_str = lifetime_display(l1);
+                                let l2 = arg2.expect_region();
+                                let l2_str = lifetime_display(l2);
+                                if l1 != l2 {
+                                    values.0.push_highlighted(l1_str);
+                                    values.1.push_highlighted(l2_str);
+                                } else if l1.is_bound() || self.tcx.sess.opts.verbose {
+                                    values.0.push_normal(l1_str);
+                                    values.1.push_normal(l2_str);
+                                } else {
+                                    values.0.push_normal("'_");
+                                    values.1.push_normal("'_");
+                                }
+                            }
+                            ty::GenericArgKind::Type(ta1) => {
+                                let ta2 = arg2.expect_ty();
+                                if ta1 == ta2 && !self.tcx.sess.opts.verbose {
+                                    values.0.push_normal("_");
+                                    values.1.push_normal("_");
+                                } else {
+                                    recurse(ta1, ta2, &mut values);
+                                }
+                            }
+                            // We're comparing two types with the same path, so we compare the type
+                            // arguments for both. If they are the same, do not highlight and elide
+                            // from the output.
+                            //     Foo<_, Bar>
+                            //     Foo<_, Qux>
+                            //         ^ elided type as this type argument was the same in both sides
+
+                            // Do the same for const arguments, if they are equal, do not highlight and
+                            // elide them from the output.
+                            ty::GenericArgKind::Const(ca1) => {
+                                let ca2 = arg2.expect_const();
+                                maybe_highlight(ca1, ca2, &mut values, self.tcx);
+                            }
                         }
-                        self.push_comma(&mut values.0, &mut values.1, len, i);
-                    }
-
-                    // Do the same for const arguments, if they are equal, do not highlight and
-                    // elide them from the output.
-                    let const_arguments = sub1.consts().zip(sub2.consts());
-                    for (i, (ca1, ca2)) in const_arguments.enumerate() {
-                        let i = i + consts_offset;
-                        maybe_highlight(ca1, ca2, &mut values, self.tcx);
-                        self.push_comma(&mut values.0, &mut values.1, len, i);
                     }
 
                     // Close the type argument bracket.
-                    // Only draw `<...>` if there are lifetime/type arguments.
+                    // Only draw `<...>` if there are arguments.
                     if len > 0 {
                         values.0.push_normal(">");
                         values.1.push_normal(">");
@@ -1244,17 +1235,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     //     Foo<Bar<Qux>
                     //         ------- this type argument is exactly the same as the other type
                     //     Bar<Qux>
-                    if self
-                        .cmp_type_arg(
-                            &mut values.0,
-                            &mut values.1,
-                            path1.clone(),
-                            sub_no_defaults_1,
-                            path2.clone(),
-                            t2,
-                        )
-                        .is_some()
-                    {
+                    if self.cmp_type_arg(
+                        &mut values.0,
+                        &mut values.1,
+                        path1.clone(),
+                        sub_no_defaults_1,
+                        path2.clone(),
+                        t2,
+                    ) {
                         return values;
                     }
                     // Check for case:
@@ -1262,17 +1250,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     //     Bar<Qux>
                     //     Foo<Bar<Qux>>
                     //         ------- this type argument is exactly the same as the other type
-                    if self
-                        .cmp_type_arg(
-                            &mut values.1,
-                            &mut values.0,
-                            path2,
-                            sub_no_defaults_2,
-                            path1,
-                            t1,
-                        )
-                        .is_some()
-                    {
+                    if self.cmp_type_arg(
+                        &mut values.1,
+                        &mut values.0,
+                        path2,
+                        sub_no_defaults_2,
+                        path1,
+                        t1,
+                    ) {
                         return values;
                     }
 
@@ -1343,8 +1328,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 let mut values = (DiagStyledString::normal("("), DiagStyledString::normal("("));
                 let len = args1.len();
                 for (i, (left, right)) in args1.iter().zip(args2).enumerate() {
+                    self.push_comma(&mut values.0, &mut values.1, i);
                     recurse(left, right, &mut values);
-                    self.push_comma(&mut values.0, &mut values.1, len, i);
                 }
                 if len == 1 {
                     // Keep the output for single element tuples as `(ty,)`.
@@ -1611,7 +1596,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             return;
         }
 
-        if let Some((expected, found, path)) = expected_found {
+        let mut path = None;
+        if let Some((expected, found, p)) = expected_found {
+            path = p;
             let (expected_label, found_label, exp_found) = match exp_found {
                 Mismatch::Variable(ef) => (
                     ef.expected.prefix_string(self.tcx),
@@ -1792,13 +1779,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                     &sort_string(values.expected),
                                     &sort_string(values.found),
                                 );
-                                if let Some(path) = path {
-                                    diag.note(format!(
-                                        "the full type name has been written to '{}'",
-                                        path.display(),
-                                    ));
-                                    diag.note("consider using `--verbose` to print the full type name to the console");
-                                }
                             }
                         }
                     }
@@ -1894,7 +1874,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         // It reads better to have the error origin as the final
         // thing.
-        self.note_error_origin(diag, cause, exp_found, terr, param_env);
+        self.note_error_origin(diag, cause, exp_found, terr, param_env, &mut path);
+        if let Some(path) = path {
+            diag.note(format!("the full type name has been written to '{}'", path.display()));
+            diag.note("consider using `--verbose` to print the full type name to the console");
+        }
 
         debug!(?diag);
     }
@@ -2318,7 +2302,6 @@ impl<'tcx> ObligationCause<'tcx> {
             | ObligationCauseCode::MatchExpressionArm(_)
             | ObligationCauseCode::IfExpression { .. }
             | ObligationCauseCode::LetElse
-            | ObligationCauseCode::StartFunctionType
             | ObligationCauseCode::LangFunctionType(_)
             | ObligationCauseCode::IntrinsicType
             | ObligationCauseCode::MethodReceiver => FailureCode::Error0308,
@@ -2376,9 +2359,6 @@ impl<'tcx> ObligationCause<'tcx> {
             ObligationCauseCode::MainFunctionType => {
                 ObligationCauseFailureCode::FnMainCorrectType { span }
             }
-            ObligationCauseCode::StartFunctionType => {
-                ObligationCauseFailureCode::FnStartCorrectType { span, subdiags }
-            }
             &ObligationCauseCode::LangFunctionType(lang_item_name) => {
                 ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name }
             }
@@ -2421,7 +2401,6 @@ impl<'tcx> ObligationCause<'tcx> {
                 "const is compatible with trait"
             }
             ObligationCauseCode::MainFunctionType => "`main` function has the correct type",
-            ObligationCauseCode::StartFunctionType => "`#[start]` function has the correct type",
             ObligationCauseCode::LangFunctionType(_) => "lang item function has the correct type",
             ObligationCauseCode::IntrinsicType => "intrinsic has the correct type",
             ObligationCauseCode::MethodReceiver => "method receiver has the correct type",
@@ -2442,7 +2421,6 @@ impl IntoDiagArg for ObligationCauseAsDiagArg<'_> {
                 "const_compat"
             }
             ObligationCauseCode::MainFunctionType => "fn_main_correct_type",
-            ObligationCauseCode::StartFunctionType => "fn_start_correct_type",
             ObligationCauseCode::LangFunctionType(_) => "fn_lang_correct_type",
             ObligationCauseCode::IntrinsicType => "intrinsic_correct_type",
             ObligationCauseCode::MethodReceiver => "method_correct_type",
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
index 2a487a48a8e..b9f3abc2534 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
@@ -1,8 +1,8 @@
 use core::ops::ControlFlow;
 
-use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::intravisit::{self, Visitor, VisitorExt};
+use rustc_hir::{self as hir, AmbigArg};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars as rbv;
@@ -48,7 +48,7 @@ fn find_component_for_bound_region<'tcx>(
     region_def_id: DefId,
 ) -> Option<&'tcx hir::Ty<'tcx>> {
     FindNestedTypeVisitor { tcx, region_def_id, current_index: ty::INNERMOST }
-        .visit_ty(arg)
+        .visit_ty_unambig(arg)
         .break_value()
 }
 
@@ -74,7 +74,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
         self.tcx.hir()
     }
 
-    fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
+    fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
         match arg.kind {
             hir::TyKind::BareFn(_) => {
                 self.current_index.shift_in(1);
@@ -101,7 +101,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
                     Some(rbv::ResolvedArg::EarlyBound(id)) => {
                         debug!("EarlyBound id={:?}", id);
                         if id.to_def_id() == self.region_def_id {
-                            return ControlFlow::Break(arg);
+                            return ControlFlow::Break(arg.as_unambig_ty());
                         }
                     }
 
@@ -117,7 +117,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
                         if debruijn_index == self.current_index
                             && id.to_def_id() == self.region_def_id
                         {
-                            return ControlFlow::Break(arg);
+                            return ControlFlow::Break(arg.as_unambig_ty());
                         }
                     }
 
@@ -147,7 +147,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
                 )
                 .is_break()
                 {
-                    ControlFlow::Break(arg)
+                    ControlFlow::Break(arg.as_unambig_ty())
                 } else {
                     ControlFlow::Continue(())
                 };
@@ -210,7 +210,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
         ControlFlow::Continue(())
     }
 
-    fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
+    fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
         // ignore nested types
         //
         // If you have a type like `Foo<'a, &Ty>` we
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
index 54d8a9e25ca..886581bc35f 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
@@ -4,7 +4,7 @@
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
-use rustc_hir::intravisit::Visitor;
+use rustc_hir::intravisit::VisitorExt;
 use rustc_middle::bug;
 use rustc_middle::ty::TypeVisitor;
 use tracing::debug;
@@ -87,7 +87,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             for matching_def_id in v.0 {
                 let mut hir_v =
                     super::static_impl_trait::HirTraitObjectVisitor(&mut traits, matching_def_id);
-                hir_v.visit_ty(impl_self_ty);
+                hir_v.visit_ty_unambig(impl_self_ty);
             }
 
             if traits.is_empty() {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
index 3416a17624e..dfbef39e9e1 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
@@ -3,9 +3,9 @@
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, Subdiagnostic};
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{Visitor, walk_ty};
+use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
 use rustc_hir::{
-    self as hir, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime,
+    self as hir, AmbigArg, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime,
     LifetimeName, LifetimeParamKind, MissingLifetimeKind, Node, TyKind,
 };
 use rustc_middle::ty::{
@@ -153,7 +153,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                     let mut add_label = true;
                     if let hir::FnRetTy::Return(ty) = fn_decl.output {
                         let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
-                        v.visit_ty(ty);
+                        v.visit_ty_unambig(ty);
                         if !v.0.is_empty() {
                             span = v.0.clone().into();
                             spans = v.0;
@@ -374,7 +374,7 @@ pub fn suggest_new_region_bound(
                     }
                 }
             }
-            TyKind::TraitObject(_, lt, _) => {
+            TyKind::TraitObject(_, lt) => {
                 if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res {
                     err.span_suggestion_verbose(
                         fn_return.span.shrink_to_hi(),
@@ -420,8 +420,8 @@ fn make_elided_region_spans_suggs<'a>(
 
     let mut process_consecutive_brackets =
         |span: Option<Span>, spans_suggs: &mut Vec<(Span, String)>| {
-            if span
-                .is_some_and(|span| bracket_span.map_or(true, |bracket_span| span == bracket_span))
+            if let Some(span) = span
+                && bracket_span.is_none_or(|bracket_span| span == bracket_span)
             {
                 consecutive_brackets += 1;
             } else if let Some(bracket_span) = bracket_span.take() {
@@ -500,7 +500,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                             // In that case, only the first one will get suggestions.
                             let mut traits = vec![];
                             let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
-                            hir_v.visit_ty(self_ty);
+                            hir_v.visit_ty_unambig(self_ty);
                             !traits.is_empty()
                         })
                     {
@@ -560,7 +560,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         for found_did in found_dids {
             let mut traits = vec![];
             let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
-            hir_v.visit_ty(self_ty);
+            hir_v.visit_ty_unambig(self_ty);
             for &span in &traits {
                 let subdiag = DynTraitConstraintSuggestion { span, ident };
                 subdiag.add_to_diag(err);
@@ -591,12 +591,10 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for TraitObjectVisitor {
 pub struct HirTraitObjectVisitor<'a>(pub &'a mut Vec<Span>, pub DefId);
 
 impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
-    fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
-        if let TyKind::TraitObject(
-            poly_trait_refs,
-            Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. },
-            _,
-        ) = t.kind
+    fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) {
+        if let TyKind::TraitObject(poly_trait_refs, lifetime_ptr) = t.kind
+            && let Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. } =
+                lifetime_ptr.pointer()
         {
             for ptr in poly_trait_refs {
                 if Some(self.1) == ptr.trait_ref.trait_def_id() {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
index 95dd1b28a39..bbcd28c0835 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
@@ -1,10 +1,10 @@
 //! Error Reporting for `impl` items that do not match the obligations from their `trait`.
 
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
 use rustc_hir::def::{Namespace, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::Visitor;
+use rustc_hir::intravisit::{Visitor, walk_ty};
+use rustc_hir::{self as hir, AmbigArg};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::error::ExpectedFound;
@@ -137,11 +137,13 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
         self.tcx.hir()
     }
 
-    fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
+    fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) {
         match arg.kind {
             hir::TyKind::Ref(_, ref mut_ty) => {
                 // We don't want to suggest looking into borrowing `&T` or `&Self`.
-                hir::intravisit::walk_ty(self, mut_ty.ty);
+                if let Some(ambig_ty) = mut_ty.ty.try_as_ambig_ty() {
+                    walk_ty(self, ambig_ty);
+                }
                 return;
             }
             hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
index 36270e0da78..af7e56961b7 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -167,6 +167,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             exp_span, exp_found.expected, exp_found.found,
         );
 
+        match self.tcx.coroutine_kind(cause.body_id) {
+            Some(hir::CoroutineKind::Desugared(
+                hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen,
+                _,
+            )) => (),
+            None
+            | Some(
+                hir::CoroutineKind::Coroutine(_)
+                | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _),
+            ) => return,
+        }
+
         if let ObligationCauseCode::CompareImplItem { .. } = cause.code() {
             return;
         }
@@ -643,7 +655,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     && let ty::Ref(found_region, _, _) = found.kind()
                     && expected_region.is_bound()
                     && !found_region.is_bound()
-                    && let hir::TyKind::Infer = arg_hir.kind
+                    && let hir::TyKind::Infer(()) = arg_hir.kind
                 {
                     // If the expected region is late bound, the found region is not, and users are asking compiler
                     // to infer the type, we can suggest adding `: &_`.
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index c40ba330845..5021fd8bf83 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -462,6 +462,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             err.note(
                                 "`#[target_feature]` functions do not implement the `Fn` traits",
                             );
+                            err.note(
+                                "try casting the function to a `fn` pointer or wrapping it in a closure",
+                            );
                         }
 
                         self.try_to_add_help_message(
@@ -580,8 +583,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             self.tcx.hir_node_by_def_id(obligation.cause.body_id)
                             && let hir::ItemKind::Impl(impl_) = item.kind
                             && let None = impl_.of_trait
-                            && let hir::TyKind::TraitObject(_, _, syntax) = impl_.self_ty.kind
-                            && let TraitObjectSyntax::None = syntax
+                            && let hir::TyKind::TraitObject(_, tagged_ptr) = impl_.self_ty.kind
+                            && let TraitObjectSyntax::None = tagged_ptr.tag()
                             && impl_.self_ty.span.edition().at_least_rust_2021()
                         {
                             // Silence the dyn-compatibility error in favor of the missing dyn on
@@ -1338,20 +1341,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     let derive_better_type_error =
                         |alias_term: ty::AliasTerm<'tcx>, expected_term: ty::Term<'tcx>| {
                             let ocx = ObligationCtxt::new(self);
-                            let normalized_term = match expected_term.unpack() {
-                                ty::TermKind::Ty(_) => self.next_ty_var(DUMMY_SP).into(),
-                                ty::TermKind::Const(_) => self.next_const_var(DUMMY_SP).into(),
-                            };
-                            ocx.register_obligation(Obligation::new(
-                                self.tcx,
-                                ObligationCause::dummy(),
+
+                            let Ok(normalized_term) = ocx.structurally_normalize_term(
+                                &ObligationCause::dummy(),
                                 obligation.param_env,
-                                ty::PredicateKind::NormalizesTo(ty::NormalizesTo {
-                                    alias: alias_term,
-                                    term: normalized_term,
-                                }),
-                            ));
-                            let _ = ocx.select_where_possible();
+                                alias_term.to_term(self.tcx),
+                            ) else {
+                                return None;
+                            };
+
                             if let Err(terr) = ocx.eq(
                                 &ObligationCause::dummy(),
                                 obligation.param_env,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index cd4f77bb4cf..8111983c539 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -11,7 +11,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{self as hir, LangItem};
+use rustc_hir::{self as hir, AmbigArg, LangItem};
 use rustc_infer::traits::{
     DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode,
     PredicateObligation, SelectionError,
@@ -87,9 +87,9 @@ impl<'v> Visitor<'v> for FindExprBySpan<'v> {
         }
     }
 
-    fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+    fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
         if self.span == ty.span {
-            self.ty_result = Some(ty);
+            self.ty_result = Some(ty.as_unambig_ty());
         } else {
             hir::intravisit::walk_ty(self, ty);
         }
@@ -433,33 +433,19 @@ pub fn report_dyn_incompatibility<'tcx>(
         hir::Node::Item(item) => Some(item.ident.span),
         _ => None,
     });
+
     let mut err = struct_span_code_err!(
         tcx.dcx(),
         span,
         E0038,
-        "the trait `{}` cannot be made into an object",
+        "the {} `{}` is not dyn compatible",
+        tcx.def_descr(trait_def_id),
         trait_str
     );
-    err.span_label(span, format!("`{trait_str}` cannot be made into an object"));
-
-    if let Some(hir_id) = hir_id
-        && let hir::Node::Ty(ty) = tcx.hir_node(hir_id)
-        && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind
-    {
-        let mut hir_id = hir_id;
-        while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) {
-            hir_id = ty.hir_id;
-        }
-        if tcx.parent_hir_node(hir_id).fn_sig().is_some() {
-            // Do not suggest `impl Trait` when dealing with things like super-traits.
-            err.span_suggestion_verbose(
-                ty.span.until(trait_ref.span),
-                "consider using an opaque type instead",
-                "impl ",
-                Applicability::MaybeIncorrect,
-            );
-        }
-    }
+    err.span_label(span, format!("`{trait_str}` is not dyn compatible"));
+
+    attempt_dyn_to_impl_suggestion(tcx, hir_id, &mut err);
+
     let mut reported_violations = FxIndexSet::default();
     let mut multi_span = vec![];
     let mut messages = vec![];
@@ -474,7 +460,7 @@ pub fn report_dyn_incompatibility<'tcx>(
         if reported_violations.insert(violation.clone()) {
             let spans = violation.spans();
             let msg = if trait_span.is_none() || spans.is_empty() {
-                format!("the trait cannot be made into an object because {}", violation.error_msg())
+                format!("the trait is not dyn compatible because {}", violation.error_msg())
             } else {
                 format!("...because {}", violation.error_msg())
             };
@@ -491,7 +477,7 @@ pub fn report_dyn_incompatibility<'tcx>(
     let has_multi_span = !multi_span.is_empty();
     let mut note_span = MultiSpan::from_spans(multi_span.clone());
     if let (Some(trait_span), true) = (trait_span, has_multi_span) {
-        note_span.push_span_label(trait_span, "this trait cannot be made into an object...");
+        note_span.push_span_label(trait_span, "this trait is not dyn compatible...");
     }
     for (span, msg) in iter::zip(multi_span, messages) {
         note_span.push_span_label(span, msg);
@@ -499,16 +485,12 @@ pub fn report_dyn_incompatibility<'tcx>(
     // FIXME(dyn_compat_renaming): Update the URL.
     err.span_note(
         note_span,
-        "for a trait to be \"dyn-compatible\" it needs to allow building a vtable to allow the call \
-         to be resolvable dynamically; for more information visit \
-         <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
+        "for a trait to be dyn compatible it needs to allow building a vtable\n\
+        for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
     );
 
     // Only provide the help if its a local trait, otherwise it's not actionable.
     if trait_span.is_some() {
-        let mut reported_violations: Vec<_> = reported_violations.into_iter().collect();
-        reported_violations.sort();
-
         let mut potential_solutions: Vec<_> =
             reported_violations.into_iter().map(|violation| violation.solution()).collect();
         potential_solutions.sort();
@@ -519,68 +501,116 @@ pub fn report_dyn_incompatibility<'tcx>(
         }
     }
 
+    attempt_dyn_to_enum_suggestion(tcx, trait_def_id, &*trait_str, &mut err);
+
+    err
+}
+
+/// Attempt to suggest converting the `dyn Trait` argument to an enumeration
+/// over the types that implement `Trait`.
+fn attempt_dyn_to_enum_suggestion(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+    trait_str: &str,
+    err: &mut Diag<'_>,
+) {
     let impls_of = tcx.trait_impls_of(trait_def_id);
-    let impls = if impls_of.blanket_impls().is_empty() {
-        impls_of
-            .non_blanket_impls()
-            .values()
-            .flatten()
-            .filter(|def_id| {
-                !matches!(tcx.type_of(*def_id).instantiate_identity().kind(), ty::Dynamic(..))
-            })
-            .collect::<Vec<_>>()
-    } else {
-        vec![]
-    };
-    let externally_visible = if !impls.is_empty()
-        && let Some(def_id) = trait_def_id.as_local()
+
+    if !impls_of.blanket_impls().is_empty() {
+        return;
+    }
+
+    let concrete_impls: Option<Vec<Ty<'_>>> = impls_of
+        .non_blanket_impls()
+        .values()
+        .flatten()
+        .map(|impl_id| {
+            // Don't suggest conversion to enum if the impl types have type parameters.
+            // It's unlikely the user wants to define a generic enum.
+            let Some(impl_type) = tcx.type_of(*impl_id).no_bound_vars() else { return None };
+
+            // Obviously unsized impl types won't be usable in an enum.
+            // Note: this doesn't use `Ty::is_trivially_sized` because that function
+            // defaults to assuming that things are *not* sized, whereas we want to
+            // fall back to assuming that things may be sized.
+            match impl_type.kind() {
+                ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::DynKind::Dyn) => {
+                    return None;
+                }
+                _ => {}
+            }
+            Some(impl_type)
+        })
+        .collect();
+    let Some(concrete_impls) = concrete_impls else { return };
+
+    const MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM: usize = 9;
+    if concrete_impls.is_empty() || concrete_impls.len() > MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM {
+        return;
+    }
+
+    let externally_visible = if let Some(def_id) = trait_def_id.as_local() {
         // We may be executing this during typeck, which would result in cycle
         // if we used effective_visibilities query, which looks into opaque types
         // (and therefore calls typeck).
-        && tcx.resolutions(()).effective_visibilities.is_exported(def_id)
-    {
-        true
+        tcx.resolutions(()).effective_visibilities.is_exported(def_id)
     } else {
         false
     };
-    match &impls[..] {
-        [] => {}
-        _ if impls.len() > 9 => {}
-        [only] if externally_visible => {
-            err.help(with_no_trimmed_paths!(format!(
-                "only type `{}` is seen to implement the trait in this crate, consider using it \
-                 directly instead",
-                tcx.type_of(*only).instantiate_identity(),
-            )));
-        }
-        [only] => {
-            err.help(with_no_trimmed_paths!(format!(
-                "only type `{}` implements the trait, consider using it directly instead",
-                tcx.type_of(*only).instantiate_identity(),
-            )));
-        }
-        impls => {
-            let types = impls
-                .iter()
-                .map(|t| {
-                    with_no_trimmed_paths!(format!("  {}", tcx.type_of(*t).instantiate_identity(),))
-                })
-                .collect::<Vec<_>>();
-            err.help(format!(
-                "the following types implement the trait, consider defining an enum where each \
-                 variant holds one of these types, implementing `{}` for this new enum and using \
-                 it instead:\n{}",
-                trait_str,
-                types.join("\n"),
-            ));
-        }
+
+    if let [only_impl] = &concrete_impls[..] {
+        let within = if externally_visible { " within this crate" } else { "" };
+        err.help(with_no_trimmed_paths!(format!(
+            "only type `{only_impl}` implements `{trait_str}`{within}; \
+            consider using it directly instead."
+        )));
+    } else {
+        let types = concrete_impls
+            .iter()
+            .map(|t| with_no_trimmed_paths!(format!("  {}", t)))
+            .collect::<Vec<String>>()
+            .join("\n");
+
+        err.help(format!(
+            "the following types implement `{trait_str}`:\n\
+             {types}\n\
+             consider defining an enum where each variant holds one of these types,\n\
+             implementing `{trait_str}` for this new enum and using it instead",
+        ));
     }
+
     if externally_visible {
         err.note(format!(
-            "`{trait_str}` can be implemented in other crates; if you want to support your users \
+            "`{trait_str}` may be implemented in other crates; if you want to support your users \
              passing their own types here, you can't refer to a specific type",
         ));
     }
+}
 
-    err
+/// Attempt to suggest that a `dyn Trait` argument or return type be converted
+/// to use `impl Trait`.
+fn attempt_dyn_to_impl_suggestion(tcx: TyCtxt<'_>, hir_id: Option<hir::HirId>, err: &mut Diag<'_>) {
+    let Some(hir_id) = hir_id else { return };
+    let hir::Node::Ty(ty) = tcx.hir_node(hir_id) else { return };
+    let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind else { return };
+
+    // Only suggest converting `dyn` to `impl` if we're in a function signature.
+    // This ensures that we don't suggest converting e.g.
+    //   `type Alias = Box<dyn DynIncompatibleTrait>;` to
+    //   `type Alias = Box<impl DynIncompatibleTrait>;`
+    let Some((_id, first_non_type_parent_node)) =
+        tcx.hir().parent_iter(hir_id).find(|(_id, node)| !matches!(node, hir::Node::Ty(_)))
+    else {
+        return;
+    };
+    if first_non_type_parent_node.fn_sig().is_none() {
+        return;
+    }
+
+    err.span_suggestion_verbose(
+        ty.span.until(trait_ref.span),
+        "consider using an opaque type instead",
+        "impl ",
+        Applicability::MaybeIncorrect,
+    );
 }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index 2d932e36470..4e0b097db4c 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt};
 use rustc_parse_format::{ParseMode, Parser, Piece, Position};
 use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
-use rustc_span::{Span, Symbol, kw, sym};
+use rustc_span::{Ident, Span, Symbol, kw, sym};
 use tracing::{debug, info};
 use {rustc_attr_parsing as attr, rustc_hir as hir};
 
@@ -375,7 +375,7 @@ impl IgnoredDiagnosticOption {
 #[help]
 pub struct UnknownFormatParameterForOnUnimplementedAttr {
     argument_name: Symbol,
-    trait_name: Symbol,
+    trait_name: Ident,
 }
 
 #[derive(LintDiagnostic)]
@@ -792,7 +792,7 @@ impl<'tcx> OnUnimplementedFormatString {
             tcx.trait_id_of_impl(item_def_id)
                 .expect("expected `on_unimplemented` to correspond to a trait")
         };
-        let trait_name = tcx.item_name(trait_def_id);
+        let trait_name = tcx.item_ident(trait_def_id);
         let generics = tcx.generics_of(item_def_id);
         let s = self.symbol.as_str();
         let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
@@ -821,7 +821,11 @@ impl<'tcx> OnUnimplementedFormatString {
                         Position::ArgumentNamed(s) => {
                             match Symbol::intern(s) {
                                 // `{ThisTraitsName}` is allowed
-                                s if s == trait_name && !self.is_diagnostic_namespace_variant => (),
+                                s if s == trait_name.name
+                                    && !self.is_diagnostic_namespace_variant =>
+                                {
+                                    ()
+                                }
                                 s if ALLOWED_FORMAT_SYMBOLS.contains(&s)
                                     && !self.is_diagnostic_namespace_variant =>
                                 {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index c2e73b732d3..471105773e2 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -14,14 +14,13 @@ use rustc_errors::{
     Applicability, Diag, EmissionGuarantee, MultiSpan, Style, SuggestionStyle, pluralize,
     struct_span_code_err,
 };
-use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::Visitor;
+use rustc_hir::intravisit::{Visitor, VisitorExt};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
-    CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node, expr_needs_parens,
-    is_range_literal,
+    self as hir, AmbigArg, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node,
+    expr_needs_parens, is_range_literal,
 };
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk};
 use rustc_middle::hir::map;
@@ -179,7 +178,7 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
         let mut ty_spans = vec![];
         for input in fn_sig.decl.inputs {
             ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id }
-                .visit_ty(input);
+                .visit_ty_unambig(input);
         }
         // The type param `T: Trait` we will suggest to introduce.
         let type_param = format!("{type_param_name}: {bound_str}");
@@ -2740,7 +2739,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             | ObligationCauseCode::IfExpression { .. }
             | ObligationCauseCode::IfExpressionWithNoElse
             | ObligationCauseCode::MainFunctionType
-            | ObligationCauseCode::StartFunctionType
             | ObligationCauseCode::LangFunctionType(_)
             | ObligationCauseCode::IntrinsicType
             | ObligationCauseCode::MethodReceiver
@@ -3075,7 +3073,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 }
                 if let Some(ty) = ty {
                     match ty.kind {
-                        hir::TyKind::TraitObject(traits, _, _) => {
+                        hir::TyKind::TraitObject(traits, _) => {
                             let (span, kw) = match traits {
                                 [first, ..] if first.span.lo() == ty.span.lo() => {
                                     // Missing `dyn` in front of trait object.
@@ -5066,7 +5064,7 @@ pub struct SelfVisitor<'v> {
 }
 
 impl<'v> Visitor<'v> for SelfVisitor<'v> {
-    fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+    fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
         if let hir::TyKind::Path(path) = ty.kind
             && let hir::QPath::TypeRelative(inner_ty, segment) = path
             && (Some(segment.ident.name) == self.name || self.name.is_none())
@@ -5074,7 +5072,7 @@ impl<'v> Visitor<'v> for SelfVisitor<'v> {
             && let hir::QPath::Resolved(None, inner_path) = inner_path
             && let Res::SelfTyAlias { .. } = inner_path.res
         {
-            self.paths.push(ty);
+            self.paths.push(ty.as_unambig_ty());
         }
         hir::intravisit::walk_ty(self, ty);
     }
@@ -5188,7 +5186,7 @@ struct ReplaceImplTraitVisitor<'a> {
 }
 
 impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> {
-    fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) {
+    fn visit_ty(&mut self, t: &'hir hir::Ty<'hir, AmbigArg>) {
         if let hir::TyKind::Path(hir::QPath::Resolved(
             None,
             hir::Path { res: Res::Def(_, segment_did), .. },
@@ -5481,7 +5479,7 @@ impl<'v> Visitor<'v> for FindTypeParam {
         // Skip where-clauses, to avoid suggesting indirection for type parameters found there.
     }
 
-    fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
+    fn visit_ty(&mut self, ty: &hir::Ty<'_, AmbigArg>) {
         // We collect the spans of all uses of the "bare" type param, like in `field: T` or
         // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
         // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 53a4e5031c6..2dfa72972ba 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -6,11 +6,10 @@ use rustc_errors::{
     Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
     EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
 };
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{Visitor, walk_ty};
-use rustc_hir::{FnRetTy, GenericParamKind, Node};
+use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
+use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath};
 use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty, TyCtxt};
@@ -579,7 +578,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
             }
 
             impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
-                fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+                fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
                     let make_suggestion = |ident: Ident| {
                         if ident.name == kw::Empty && ident.span.is_empty() {
                             format!("{}, ", self.suggestion_param_name)
@@ -642,16 +641,16 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
             if let Some(fn_decl) = node.fn_decl()
                 && let hir::FnRetTy::Return(ty) = fn_decl.output
             {
-                visitor.visit_ty(ty);
+                visitor.visit_ty_unambig(ty);
             }
             if visitor.suggestions.is_empty() {
                 // Do not suggest constraining the `&self` param, but rather the return type.
                 // If that is wrong (because it is not sufficient), a follow up error will tell the
                 // user to fix it. This way we lower the chances of *over* constraining, but still
                 // get the cake of "correctly" contrained in two steps.
-                visitor.visit_ty(self.ty_sup);
+                visitor.visit_ty_unambig(self.ty_sup);
             }
-            visitor.visit_ty(self.ty_sub);
+            visitor.visit_ty_unambig(self.ty_sub);
             if visitor.suggestions.is_empty() {
                 return false;
             }
@@ -1695,13 +1694,6 @@ pub enum ObligationCauseFailureCode {
         #[primary_span]
         span: Span,
     },
-    #[diag(trait_selection_oc_fn_start_correct_type, code = E0308)]
-    FnStartCorrectType {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
     #[diag(trait_selection_oc_fn_lang_correct_type, code = E0308)]
     FnLangCorrectType {
         #[primary_span]
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 4498beff4ea..2b7da4bc5ff 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -513,8 +513,27 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
             _ => ChildMode::PassThrough,
         };
 
+        let nested_goals = candidate.instantiate_nested_goals(self.span());
+
+        // If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as
+        // an actual candidate, instead we should treat them as if the impl was never considered to
+        // have potentially applied. As if `impl<A, R> Trait for for<..> fn(..A) -> R` was written
+        // instead of `impl<T: FnPtr> Trait for T`.
+        //
+        // We do this as a separate loop so that we do not choose to tell the user about some nested
+        // goal before we encounter a `T: FnPtr` nested goal.
+        for nested_goal in &nested_goals {
+            if let Some(fn_ptr_trait) = tcx.lang_items().fn_ptr_trait()
+                && let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
+                && poly_trait_pred.def_id() == fn_ptr_trait
+                && let Err(NoSolution) = nested_goal.result()
+            {
+                return ControlFlow::Break(self.obligation.clone());
+            }
+        }
+
         let mut impl_where_bound_count = 0;
-        for nested_goal in candidate.instantiate_nested_goals(self.span()) {
+        for nested_goal in nested_goals {
             trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
 
             let make_obligation = |cause| Obligation {
@@ -605,7 +624,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
     }
 }
 
-#[derive(Copy, Clone)]
+#[derive(Debug, Copy, Clone)]
 enum ChildMode<'tcx> {
     // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
     // and skip all `GoalSource::Misc`, which represent useless obligations
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index e27143f1396..50d47d20e1a 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -709,7 +709,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
             if matches!(ty.kind(), ty::Alias(..)) {
                 let ocx = ObligationCtxt::new(infcx);
                 ty = ocx
-                    .structurally_normalize(&ObligationCause::dummy(), param_env, ty)
+                    .structurally_normalize_ty(&ObligationCause::dummy(), param_env, ty)
                     .map_err(|_| ())?;
                 if !ocx.select_where_possible().is_empty() {
                     return Err(());
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index d2abd881c45..66491d9abe1 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -19,6 +19,7 @@ use rustc_middle::ty::{
     TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
 };
 use rustc_span::Span;
+use rustc_type_ir::elaborate;
 use smallvec::SmallVec;
 use tracing::{debug, instrument};
 
@@ -39,7 +40,7 @@ pub fn hir_ty_lowering_dyn_compatibility_violations(
     trait_def_id: DefId,
 ) -> Vec<DynCompatibilityViolation> {
     debug_assert!(tcx.generics_of(trait_def_id).has_self);
-    tcx.supertrait_def_ids(trait_def_id)
+    elaborate::supertrait_def_ids(tcx, trait_def_id)
         .map(|def_id| predicates_reference_self(tcx, def_id, true))
         .filter(|spans| !spans.is_empty())
         .map(DynCompatibilityViolation::SupertraitSelf)
@@ -52,9 +53,8 @@ fn dyn_compatibility_violations(
 ) -> &'_ [DynCompatibilityViolation] {
     debug_assert!(tcx.generics_of(trait_def_id).has_self);
     debug!("dyn_compatibility_violations: {:?}", trait_def_id);
-
     tcx.arena.alloc_from_iter(
-        tcx.supertrait_def_ids(trait_def_id)
+        elaborate::supertrait_def_ids(tcx, trait_def_id)
             .flat_map(|def_id| dyn_compatibility_violations_for_trait(tcx, def_id)),
     )
 }
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 5e270b62b00..4a3983fca31 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -319,7 +319,7 @@ where
         self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut())
     }
 
-    pub fn structurally_normalize(
+    pub fn structurally_normalize_ty(
         &self,
         cause: &ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
@@ -327,7 +327,7 @@ where
     ) -> Result<Ty<'tcx>, Vec<E>> {
         self.infcx
             .at(cause, param_env)
-            .structurally_normalize(value, &mut **self.engine.borrow_mut())
+            .structurally_normalize_ty(value, &mut **self.engine.borrow_mut())
     }
 
     pub fn structurally_normalize_const(
@@ -340,4 +340,15 @@ where
             .at(cause, param_env)
             .structurally_normalize_const(value, &mut **self.engine.borrow_mut())
     }
+
+    pub fn structurally_normalize_term(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        value: ty::Term<'tcx>,
+    ) -> Result<ty::Term<'tcx>, Vec<E>> {
+        self.infcx
+            .at(cause, param_env)
+            .structurally_normalize_term(value, &mut **self.engine.borrow_mut())
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index da16a742099..fe5ad003a7e 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -66,9 +66,9 @@ pub use self::specialize::{
 };
 pub use self::structural_normalize::StructurallyNormalizeExt;
 pub use self::util::{
-    BoundVarReplacer, PlaceholderReplacer, TraitAliasExpander, TraitAliasExpansionInfo, elaborate,
-    expand_trait_aliases, impl_item_is_final, supertraits,
-    transitive_bounds_that_define_assoc_item, upcast_choices, with_replaced_escaping_bound_vars,
+    BoundVarReplacer, PlaceholderReplacer, elaborate, expand_trait_aliases, impl_item_is_final,
+    supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, upcast_choices,
+    with_replaced_escaping_bound_vars,
 };
 use crate::error_reporting::InferCtxtErrorExt;
 use crate::infer::outlives::env::OutlivesEnvironment;
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index d59cf88875e..537b042bde5 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -18,6 +18,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, Term, Ty, TyCtxt, TypingMode, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::sym;
+use rustc_type_ir::elaborate;
 use thin_vec::thin_vec;
 use tracing::{debug, instrument};
 
@@ -836,8 +837,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
     if tcx.is_impl_trait_in_trait(obligation.predicate.def_id)
         && let Some(out_trait_def_id) = data.principal_def_id()
         && let rpitit_trait_def_id = tcx.parent(obligation.predicate.def_id)
-        && tcx
-            .supertrait_def_ids(out_trait_def_id)
+        && elaborate::supertrait_def_ids(tcx, out_trait_def_id)
             .any(|trait_def_id| trait_def_id == rpitit_trait_def_id)
     {
         candidate_set.push_candidate(ProjectionCandidate::ObjectRpitit);
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 4004e354dc1..26ba1511b54 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -6,8 +6,7 @@ use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument};
 
 use crate::traits::query::NoSolution;
-use crate::traits::query::normalize::QueryNormalizeExt;
-use crate::traits::{Normalized, ObligationCause, ObligationCtxt};
+use crate::traits::{ObligationCause, ObligationCtxt};
 
 /// This returns true if the type `ty` is "trivial" for
 /// dropck-outlives -- that is, if it doesn't require any types to
@@ -172,13 +171,18 @@ pub fn compute_dropck_outlives_inner<'tcx>(
         // do not themselves define a destructor", more or less. We have
         // to push them onto the stack to be expanded.
         for ty in constraints.dtorck_types.drain(..) {
-            let Normalized { value: ty, obligations } =
-                ocx.infcx.at(&cause, param_env).query_normalize(ty)?;
-            ocx.register_obligations(obligations);
+            let normalized_ty = ocx.normalize(&cause, param_env, ty);
 
-            debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
+            let errors = ocx.select_where_possible();
+            if !errors.is_empty() {
+                debug!("failed to normalize dtorck type: {ty} ~> {errors:#?}");
+                return Err(NoSolution);
+            }
+
+            let normalized_ty = ocx.infcx.resolve_vars_if_possible(normalized_ty);
+            debug!("dropck_outlives: ty from dtorck_types = {:?}", normalized_ty);
 
-            match ty.kind() {
+            match normalized_ty.kind() {
                 // All parameters live for the duration of the
                 // function.
                 ty::Param(..) => {}
@@ -186,12 +190,12 @@ pub fn compute_dropck_outlives_inner<'tcx>(
                 // A projection that we couldn't resolve - it
                 // might have a destructor.
                 ty::Alias(..) => {
-                    result.kinds.push(ty.into());
+                    result.kinds.push(normalized_ty.into());
                 }
 
                 _ => {
-                    if ty_set.insert(ty) {
-                        ty_stack.push((ty, depth + 1));
+                    if ty_set.insert(normalized_ty) {
+                        ty_stack.push((normalized_ty, depth + 1));
                     }
                 }
             }
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 b370f802052..13a6744c2e9 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -18,7 +18,7 @@ use rustc_infer::traits::{
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode};
 use rustc_middle::{bug, span_bug};
-use rustc_type_ir::Interner;
+use rustc_type_ir::{Interner, elaborate};
 use tracing::{debug, instrument, trace};
 
 use super::SelectionCandidate::*;
@@ -1003,8 +1003,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     let a_auto_traits: FxIndexSet<DefId> = a_data
                         .auto_traits()
                         .chain(principal_def_id_a.into_iter().flat_map(|principal_def_id| {
-                            self.tcx()
-                                .supertrait_def_ids(principal_def_id)
+                            elaborate::supertrait_def_ids(self.tcx(), principal_def_id)
                                 .filter(|def_id| self.tcx().trait_is_auto(*def_id))
                         }))
                         .collect();
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 5581ea46882..0cc0d7f786b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -32,6 +32,7 @@ use rustc_middle::ty::{
     TypingMode, Upcast,
 };
 use rustc_span::{Symbol, sym};
+use rustc_type_ir::elaborate;
 use tracing::{debug, instrument, trace};
 
 use self::EvaluationResult::*;
@@ -2531,7 +2532,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         let a_auto_traits: FxIndexSet<DefId> = a_data
             .auto_traits()
             .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
-                tcx.supertrait_def_ids(principal_def_id).filter(|def_id| tcx.trait_is_auto(*def_id))
+                elaborate::supertrait_def_ids(tcx, principal_def_id)
+                    .filter(|def_id| tcx.trait_is_auto(*def_id))
             }))
             .collect();
 
diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
index f8e8f2176c1..e6d5d336b8d 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
@@ -7,44 +7,12 @@ use crate::traits::{NormalizeExt, Obligation};
 
 #[extension(pub trait StructurallyNormalizeExt<'tcx>)]
 impl<'tcx> At<'_, 'tcx> {
-    fn structurally_normalize<E: 'tcx>(
+    fn structurally_normalize_ty<E: 'tcx>(
         &self,
         ty: Ty<'tcx>,
         fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
     ) -> Result<Ty<'tcx>, Vec<E>> {
-        assert!(!ty.is_ty_var(), "should have resolved vars before calling");
-
-        if self.infcx.next_trait_solver() {
-            let ty::Alias(..) = *ty.kind() else {
-                return Ok(ty);
-            };
-
-            let new_infer_ty = self.infcx.next_ty_var(self.cause.span);
-
-            // We simply emit an `alias-eq` goal here, since that will take care of
-            // normalizing the LHS of the projection until it is a rigid projection
-            // (or a not-yet-defined opaque in scope).
-            let obligation = Obligation::new(
-                self.infcx.tcx,
-                self.cause.clone(),
-                self.param_env,
-                ty::PredicateKind::AliasRelate(
-                    ty.into(),
-                    new_infer_ty.into(),
-                    ty::AliasRelationDirection::Equate,
-                ),
-            );
-
-            fulfill_cx.register_predicate_obligation(self.infcx, obligation);
-            let errors = fulfill_cx.select_where_possible(self.infcx);
-            if !errors.is_empty() {
-                return Err(errors);
-            }
-
-            Ok(self.infcx.resolve_vars_if_possible(new_infer_ty))
-        } else {
-            Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx))
-        }
+        self.structurally_normalize_term(ty.into(), fulfill_cx).map(|term| term.expect_type())
     }
 
     fn structurally_normalize_const<E: 'tcx>(
@@ -52,14 +20,29 @@ impl<'tcx> At<'_, 'tcx> {
         ct: ty::Const<'tcx>,
         fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
     ) -> Result<ty::Const<'tcx>, Vec<E>> {
-        assert!(!ct.is_ct_infer(), "should have resolved vars before calling");
+        if self.infcx.tcx.features().generic_const_exprs() {
+            return Ok(super::evaluate_const(&self.infcx, ct, self.param_env));
+        }
+
+        self.structurally_normalize_term(ct.into(), fulfill_cx).map(|term| term.expect_const())
+    }
+
+    fn structurally_normalize_term<E: 'tcx>(
+        &self,
+        term: ty::Term<'tcx>,
+        fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
+    ) -> Result<ty::Term<'tcx>, Vec<E>> {
+        assert!(!term.is_infer(), "should have resolved vars before calling");
 
         if self.infcx.next_trait_solver() {
-            let ty::ConstKind::Unevaluated(..) = ct.kind() else {
-                return Ok(ct);
-            };
+            if let None = term.to_alias_term() {
+                return Ok(term);
+            }
 
-            let new_infer_ct = self.infcx.next_const_var(self.cause.span);
+            let new_infer = match term.unpack() {
+                ty::TermKind::Ty(_) => self.infcx.next_ty_var(self.cause.span).into(),
+                ty::TermKind::Const(_) => self.infcx.next_const_var(self.cause.span).into(),
+            };
 
             // We simply emit an `alias-eq` goal here, since that will take care of
             // normalizing the LHS of the projection until it is a rigid projection
@@ -68,11 +51,7 @@ impl<'tcx> At<'_, 'tcx> {
                 self.infcx.tcx,
                 self.cause.clone(),
                 self.param_env,
-                ty::PredicateKind::AliasRelate(
-                    ct.into(),
-                    new_infer_ct.into(),
-                    ty::AliasRelationDirection::Equate,
-                ),
+                ty::PredicateKind::AliasRelate(term, new_infer, ty::AliasRelationDirection::Equate),
             );
 
             fulfill_cx.register_predicate_obligation(self.infcx, obligation);
@@ -81,11 +60,9 @@ impl<'tcx> At<'_, 'tcx> {
                 return Err(errors);
             }
 
-            Ok(self.infcx.resolve_vars_if_possible(new_infer_ct))
-        } else if self.infcx.tcx.features().generic_const_exprs() {
-            Ok(super::evaluate_const(&self.infcx, ct, self.param_env))
+            Ok(self.infcx.resolve_vars_if_possible(new_infer))
         } else {
-            Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx))
+            Ok(self.normalize(term).into_value_registering_obligations(self.infcx, fulfill_cx))
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index da1045b664a..c9fb2a757e1 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -1,162 +1,85 @@
-use std::collections::BTreeMap;
+use std::collections::{BTreeMap, VecDeque};
 
-use rustc_data_structures::fx::FxIndexMap;
-use rustc_errors::Diag;
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::InferCtxt;
 pub use rustc_infer::traits::util::*;
 use rustc_middle::bug;
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast,
+    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
 use rustc_span::Span;
 use smallvec::{SmallVec, smallvec};
 use tracing::debug;
 
-///////////////////////////////////////////////////////////////////////////
-// `TraitAliasExpander` iterator
-///////////////////////////////////////////////////////////////////////////
-
-/// "Trait alias expansion" is the process of expanding a sequence of trait
-/// references into another sequence by transitively following all trait
-/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias
-/// `trait Foo = Bar + Sync;`, and another trait alias
-/// `trait Bar = Read + Write`, then the bounds would expand to
-/// `Read + Write + Sync + Send`.
-/// Expansion is done via a DFS (depth-first search), and the `visited` field
-/// is used to avoid cycles.
-pub struct TraitAliasExpander<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    stack: Vec<TraitAliasExpansionInfo<'tcx>>,
-}
-
-/// Stores information about the expansion of a trait via a path of zero or more trait aliases.
-#[derive(Debug, Clone)]
-pub struct TraitAliasExpansionInfo<'tcx> {
-    pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>,
-}
-
-impl<'tcx> TraitAliasExpansionInfo<'tcx> {
-    fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
-        Self { path: smallvec![(trait_ref, span)] }
-    }
-
-    /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate
-    /// trait aliases.
-    pub fn label_with_exp_info(
-        &self,
-        diag: &mut Diag<'_>,
-        top_label: &'static str,
-        use_desc: &str,
-    ) {
-        diag.span_label(self.top().1, top_label);
-        if self.path.len() > 1 {
-            for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) {
-                diag.span_label(*sp, format!("referenced here ({use_desc})"));
-            }
-        }
-        if self.top().1 != self.bottom().1 {
-            // When the trait object is in a return type these two spans match, we don't want
-            // redundant labels.
-            diag.span_label(
-                self.bottom().1,
-                format!("trait alias used in trait object type ({use_desc})"),
-            );
-        }
-    }
-
-    pub fn trait_ref(&self) -> ty::PolyTraitRef<'tcx> {
-        self.top().0
-    }
-
-    pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
-        self.path.last().unwrap()
-    }
-
-    pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
-        self.path.first().unwrap()
-    }
-
-    fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
-        let mut path = self.path.clone();
-        path.push((trait_ref, span));
-
-        Self { path }
-    }
-}
-
+/// Return the trait and projection predicates that come from eagerly expanding the
+/// trait aliases in the list of clauses. For each trait predicate, record a stack
+/// of spans that trace from the user-written trait alias bound. For projection predicates,
+/// just record the span of the projection itself.
+///
+/// For trait aliases, we don't deduplicte the predicates, since we currently do not
+/// consider duplicated traits as a single trait for the purposes of our "one trait principal"
+/// restriction; however, for projections we do deduplicate them.
+///
+/// ```rust,ignore (fails)
+/// trait Bar {}
+/// trait Foo = Bar + Bar;
+///
+/// let not_object_safe: dyn Foo; // bad, two `Bar` principals.
+/// ```
 pub fn expand_trait_aliases<'tcx>(
     tcx: TyCtxt<'tcx>,
-    trait_refs: impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)>,
-) -> TraitAliasExpander<'tcx> {
-    let items: Vec<_> =
-        trait_refs.map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)).collect();
-    TraitAliasExpander { tcx, stack: items }
-}
-
-impl<'tcx> TraitAliasExpander<'tcx> {
-    /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item`
-    /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`.
-    /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a
-    /// trait alias.
-    /// The return value indicates whether `item` should be yielded to the user.
-    fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
-        let tcx = self.tcx;
-        let trait_ref = item.trait_ref();
-        let pred = trait_ref.upcast(tcx);
-
-        debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
-
-        // Don't recurse if this bound is not a trait alias.
-        let is_alias = tcx.is_trait_alias(trait_ref.def_id());
-        if !is_alias {
-            return true;
-        }
-
-        // Don't recurse if this trait alias is already on the stack for the DFS search.
-        let anon_pred = anonymize_predicate(tcx, pred);
-        if item
-            .path
-            .iter()
-            .rev()
-            .skip(1)
-            .any(|&(tr, _)| anonymize_predicate(tcx, tr.upcast(tcx)) == anon_pred)
-        {
-            return false;
-        }
-
-        // Get components of trait alias.
-        let predicates = tcx.explicit_super_predicates_of(trait_ref.def_id());
-        debug!(?predicates);
-
-        let items = predicates.skip_binder().iter().rev().filter_map(|(pred, span)| {
-            pred.instantiate_supertrait(tcx, trait_ref)
-                .as_trait_clause()
-                .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
-        });
-        debug!("expand_trait_aliases: items={:?}", items.clone().collect::<Vec<_>>());
-
-        self.stack.extend(items);
-
-        false
-    }
-}
-
-impl<'tcx> Iterator for TraitAliasExpander<'tcx> {
-    type Item = TraitAliasExpansionInfo<'tcx>;
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (self.stack.len(), None)
-    }
-
-    fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> {
-        while let Some(item) = self.stack.pop() {
-            if self.expand(&item) {
-                return Some(item);
+    clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
+) -> (
+    Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,
+    Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
+) {
+    let mut trait_preds = vec![];
+    let mut projection_preds = vec![];
+    let mut seen_projection_preds = FxHashSet::default();
+
+    let mut queue: VecDeque<_> = clauses.into_iter().map(|(p, s)| (p, smallvec![s])).collect();
+
+    while let Some((clause, spans)) = queue.pop_front() {
+        match clause.kind().skip_binder() {
+            ty::ClauseKind::Trait(trait_pred) => {
+                if tcx.is_trait_alias(trait_pred.def_id()) {
+                    queue.extend(
+                        tcx.explicit_super_predicates_of(trait_pred.def_id())
+                            .iter_identity_copied()
+                            .map(|(clause, span)| {
+                                let mut spans = spans.clone();
+                                spans.push(span);
+                                (
+                                    clause.instantiate_supertrait(
+                                        tcx,
+                                        clause.kind().rebind(trait_pred.trait_ref),
+                                    ),
+                                    spans,
+                                )
+                            }),
+                    );
+                } else {
+                    trait_preds.push((clause.kind().rebind(trait_pred), spans));
+                }
             }
+            ty::ClauseKind::Projection(projection_pred) => {
+                let projection_pred = clause.kind().rebind(projection_pred);
+                if !seen_projection_preds.insert(tcx.anonymize_bound_vars(projection_pred)) {
+                    continue;
+                }
+                projection_preds.push((projection_pred, *spans.last().unwrap()));
+            }
+            ty::ClauseKind::RegionOutlives(..)
+            | ty::ClauseKind::TypeOutlives(..)
+            | ty::ClauseKind::ConstArgHasType(_, _)
+            | ty::ClauseKind::WellFormed(_)
+            | ty::ClauseKind::ConstEvaluatable(_)
+            | ty::ClauseKind::HostEffect(..) => {}
         }
-        None
     }
+
+    (trait_preds, projection_preds)
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index 71088a598bb..5d041c2623a 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -6,13 +6,12 @@ use rustc_middle::query::Providers;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::{Clause, FnSig, ParamEnvAnd, PolyFnSig, Ty, TyCtxt, TypeFoldable};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
-use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{
     AscribeUserType, type_op_ascribe_user_type_with_span,
 };
 use rustc_trait_selection::traits::query::type_op::normalize::Normalize;
 use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate;
-use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt};
+use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
 
 pub(crate) fn provide(p: &mut Providers) {
     *p = Providers {
@@ -43,10 +42,7 @@ where
     T: fmt::Debug + TypeFoldable<TyCtxt<'tcx>>,
 {
     let (param_env, Normalize { value }) = key.into_parts();
-    let Normalized { value, obligations } =
-        ocx.infcx.at(&ObligationCause::dummy(), param_env).query_normalize(value)?;
-    ocx.register_obligations(obligations);
-    Ok(value)
+    Ok(ocx.normalize(&ObligationCause::dummy(), param_env, value))
 }
 
 fn type_op_normalize_ty<'tcx>(
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 6ce9969aefe..b00585d2922 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -197,6 +197,7 @@ pub(crate) mod rustc {
             match err {
                 LayoutError::Unknown(..)
                 | LayoutError::ReferencesError(..)
+                | LayoutError::TooGeneric(..)
                 | LayoutError::NormalizationFailure(..) => Self::UnknownLayout,
                 LayoutError::SizeOverflow(..) => Self::SizeOverflow,
                 LayoutError::Cycle(err) => Self::TypeError(*err),
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 8f9f66db1bd..f71b924b177 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -1,8 +1,8 @@
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::{self as hir, AmbigArg};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
 use rustc_middle::{bug, span_bug};
@@ -187,7 +187,7 @@ fn associated_types_for_impl_traits_in_associated_fn(
             }
 
             impl<'tcx> Visitor<'tcx> for RPITVisitor {
-                fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
+                fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
                     if let hir::TyKind::OpaqueDef(opaq) = ty.kind
                         && self.rpits.insert(opaq.def_id)
                     {
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 17be0bd0ab9..a04c7536118 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -104,14 +104,12 @@ fn map_error<'tcx>(
             // This is sometimes not a compile error if there are trivially false where clauses.
             // See `tests/ui/layout/trivial-bounds-sized.rs` for an example.
             assert!(field.layout.is_unsized(), "invalid layout error {err:#?}");
-            if !field.ty.is_sized(cx.tcx(), cx.typing_env) {
-                let guar = cx.tcx().dcx().delayed_bug(format!(
+            if cx.typing_env.param_env.caller_bounds().is_empty() {
+                cx.tcx().dcx().delayed_bug(format!(
                     "encountered unexpected unsized field in layout of {ty:?}: {field:#?}"
                 ));
-                LayoutError::ReferencesError(guar)
-            } else {
-                LayoutError::Unknown(ty)
             }
+            LayoutError::Unknown(ty)
         }
         LayoutCalculatorError::EmptyUnion => {
             // This is always a compile error.
@@ -146,6 +144,35 @@ fn univariant_uninterned<'tcx>(
     cx.calc.univariant(fields, repr, kind).map_err(|err| map_error(cx, ty, err))
 }
 
+fn validate_const_with_value<'tcx>(
+    const_: ty::Const<'tcx>,
+    ty: Ty<'tcx>,
+    cx: &LayoutCx<'tcx>,
+) -> Result<ty::Const<'tcx>, &'tcx LayoutError<'tcx>> {
+    match const_.kind() {
+        ty::ConstKind::Value(..) => Ok(const_),
+        ty::ConstKind::Error(guar) => {
+            return Err(error(cx, LayoutError::ReferencesError(guar)));
+        }
+        ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => {
+            if !const_.has_param() {
+                bug!("no generic type found in the type: {ty:?}");
+            }
+            return Err(error(cx, LayoutError::TooGeneric(ty)));
+        }
+        ty::ConstKind::Unevaluated(_) => {
+            if !const_.has_param() {
+                return Err(error(cx, LayoutError::Unknown(ty)));
+            } else {
+                return Err(error(cx, LayoutError::TooGeneric(ty)));
+            }
+        }
+        ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
+            bug!("unexpected type: {ty:?}");
+        }
+    }
+}
+
 fn layout_of_uncached<'tcx>(
     cx: &LayoutCx<'tcx>,
     ty: Ty<'tcx>,
@@ -182,12 +209,13 @@ fn layout_of_uncached<'tcx>(
                         &mut layout.backend_repr
                     {
                         if let Some(start) = start {
-                            scalar.valid_range_mut().start = start
-                                .try_to_bits(tcx, cx.typing_env)
-                                .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
+                            scalar.valid_range_mut().start =
+                                validate_const_with_value(start, ty, cx)?
+                                    .try_to_bits(tcx, cx.typing_env)
+                                    .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
                         }
                         if let Some(end) = end {
-                            let mut end = end
+                            let mut end = validate_const_with_value(end, ty, cx)?
                                 .try_to_bits(tcx, cx.typing_env)
                                 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
                             if !include_end {
@@ -319,17 +347,13 @@ fn layout_of_uncached<'tcx>(
         }
 
         // Arrays and slices.
-        ty::Array(element, mut count) => {
-            if count.has_aliases() {
-                count = tcx.normalize_erasing_regions(cx.typing_env, count);
-                if count.has_aliases() {
-                    return Err(error(cx, LayoutError::Unknown(ty)));
-                }
-            }
-
-            let count = count
+        ty::Array(element, count) => {
+            let count = validate_const_with_value(count, ty, cx)?
+                .to_valtree()
+                .0
                 .try_to_target_usize(tcx)
                 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
+
             let element = cx.layout_of(element)?;
             let size = element
                 .size
@@ -687,6 +711,9 @@ fn layout_of_uncached<'tcx>(
 
         // Types with no meaningful known layout.
         ty::Alias(..) => {
+            if ty.has_param() {
+                return Err(error(cx, LayoutError::TooGeneric(ty)));
+            }
             // NOTE(eddyb) `layout_of` query should've normalized these away,
             // if that was possible, so there's no reason to try again here.
             return Err(error(cx, LayoutError::Unknown(ty)));
@@ -696,7 +723,11 @@ fn layout_of_uncached<'tcx>(
             bug!("Layout::compute: unexpected type `{}`", ty)
         }
 
-        ty::Placeholder(..) | ty::Param(_) => {
+        ty::Param(_) => {
+            return Err(error(cx, LayoutError::TooGeneric(ty)));
+        }
+
+        ty::Placeholder(..) => {
             return Err(error(cx, LayoutError::Unknown(ty)));
         }
     })
diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs
index 10b164eae02..74e4e035c87 100644
--- a/compiler/rustc_type_ir/src/ty_kind/closure.rs
+++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs
@@ -3,9 +3,10 @@ use std::ops::ControlFlow;
 use derive_where::derive_where;
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 
+use crate::data_structures::DelayedMap;
 use crate::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region};
 use crate::inherent::*;
-use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
 use crate::{self as ty, Interner};
 
 /// A closure can be modeled as a struct that looks like:
@@ -471,6 +472,7 @@ impl<I: Interner> CoroutineClosureSignature<I> {
                         interner: cx,
                         region: env_region,
                         debruijn: ty::INNERMOST,
+                        cache: Default::default(),
                     });
                 Ty::new_tup_from_iter(
                     cx,
@@ -498,6 +500,10 @@ struct FoldEscapingRegions<I: Interner> {
     interner: I,
     debruijn: ty::DebruijnIndex,
     region: I::Region,
+
+    // Depends on `debruijn` because we may have types with regions of different
+    // debruijn depths depending on the binders we've entered.
+    cache: DelayedMap<(ty::DebruijnIndex, I::Ty), I::Ty>,
 }
 
 impl<I: Interner> TypeFolder<I> for FoldEscapingRegions<I> {
@@ -505,6 +511,18 @@ impl<I: Interner> TypeFolder<I> for FoldEscapingRegions<I> {
         self.interner
     }
 
+    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
+        if !t.has_vars_bound_at_or_above(self.debruijn) {
+            t
+        } else if let Some(&t) = self.cache.get(&(self.debruijn, t)) {
+            t
+        } else {
+            let res = t.super_fold_with(self);
+            assert!(self.cache.insert((self.debruijn, t), res));
+            res
+        }
+    }
+
     fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
     where
         T: TypeFoldable<I>,
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
index 71c3646498b..3213638afb2 100644
--- a/compiler/rustc_type_ir/src/visit.rs
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -47,6 +47,7 @@ use std::ops::ControlFlow;
 use rustc_ast_ir::visit::VisitorResult;
 use rustc_ast_ir::{try_visit, walk_visitable_list};
 use rustc_index::{Idx, IndexVec};
+use smallvec::SmallVec;
 use thin_vec::ThinVec;
 
 use crate::data_structures::Lrc;
@@ -192,6 +193,13 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for ThinVec<T> {
     }
 }
 
+impl<I: Interner, T: TypeVisitable<I>, const N: usize> TypeVisitable<I> for SmallVec<[T; N]> {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
+        walk_visitable_list!(visitor, self.iter());
+        V::Result::output()
+    }
+}
+
 // `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general
 // case, because we can't return a new slice. But note that there are a couple
 // of trivial impls of `TypeFoldable` for specific slice types elsewhere.