about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml2
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_ast/src/ast.rs38
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs40
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs40
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs4
-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_codegen_gcc/src/lib.rs1
-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/context.rs57
-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/declare.rs28
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/back/lto.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/naked_asm.rs173
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/write.rs2
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs111
-rw-r--r--compiler/rustc_hir/src/hir.rs207
-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/lib.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs37
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs60
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs20
-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_pretty/src/lib.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs21
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs27
-rw-r--r--compiler/rustc_interface/src/interface.rs14
-rw-r--r--compiler/rustc_interface/src/tests.rs6
-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/lints.rs3
-rw-r--r--compiler/rustc_lint/src/non_local_def.rs4
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs4
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs5
-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.rs7
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs28
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs4
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs9
-rw-r--r--compiler/rustc_middle/src/query/arena_cached.rs47
-rw-r--r--compiler/rustc_middle/src/query/mod.rs10
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs20
-rw-r--r--compiler/rustc_middle/src/ty/context.rs6
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs18
-rw-r--r--compiler/rustc_middle/src/values.rs8
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs18
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs182
-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/mod.rs32
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs12
-rw-r--r--compiler/rustc_next_trait_solver/Cargo.toml1
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs48
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs5
-rw-r--r--compiler/rustc_parse_format/src/lib.rs8
-rw-r--r--compiler/rustc_passes/src/check_attr.rs2
-rw-r--r--compiler/rustc_passes/src/dead.rs2
-rw-r--r--compiler/rustc_passes/src/input_stats.rs7
-rw-r--r--compiler/rustc_passes/src/stability.rs13
-rw-r--r--compiler/rustc_privacy/src/lib.rs22
-rw-r--r--compiler/rustc_session/src/session.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs4
-rw-r--r--compiler/rustc_target/src/spec/mod.rs5
-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_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/thumbv7a_nuttx_eabi.rs33
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs37
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs278
-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.rs22
-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.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs19
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs24
-rw-r--r--compiler/rustc_traits/src/type_op.rs8
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs4
-rw-r--r--library/alloc/src/bstr.rs702
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs46
-rw-r--r--library/alloc/src/lib.rs4
-rw-r--r--library/alloc/src/vec/mod.rs26
-rw-r--r--library/alloc/tests/lib.rs1
-rw-r--r--library/alloc/tests/vec_deque.rs39
-rw-r--r--library/core/src/array/mod.rs1
-rw-r--r--library/core/src/bstr.rs581
-rw-r--r--library/core/src/clone.rs10
-rw-r--r--library/core/src/lib.rs4
-rw-r--r--library/core/src/num/nonzero.rs20
-rw-r--r--library/core/tests/bstr.rs54
-rw-r--r--library/proc_macro/src/bridge/closure.rs4
-rw-r--r--library/proc_macro/src/bridge/fxhash.rs4
-rw-r--r--library/proc_macro/src/bridge/rpc.rs4
-rw-r--r--library/proc_macro/src/bridge/selfless_reify.rs2
-rw-r--r--library/proc_macro/src/lib.rs1
-rw-r--r--library/std/src/bstr.rs4
-rw-r--r--library/std/src/fs.rs1
-rw-r--r--library/std/src/lib.rs4
-rw-r--r--library/test/src/cli.rs2
-rw-r--r--library/test/src/console.rs18
-rw-r--r--library/test/src/formatters/json.rs2
-rw-r--r--library/test/src/formatters/junit.rs4
-rw-r--r--library/test/src/formatters/pretty.rs26
-rw-r--r--library/test/src/formatters/terse.rs20
-rw-r--r--library/test/src/helpers/concurrency.rs2
-rw-r--r--library/test/src/helpers/mod.rs6
-rw-r--r--library/test/src/helpers/shuffle.rs4
-rw-r--r--library/test/src/lib.rs1
-rw-r--r--library/test/src/options.rs2
-rw-r--r--library/test/src/stats/tests.rs6
-rw-r--r--library/test/src/term.rs2
-rw-r--r--library/test/src/test_result.rs6
-rw-r--r--library/test/src/tests.rs28
-rw-r--r--library/test/src/time.rs30
-rw-r--r--src/bootstrap/src/core/build_steps/gcc.rs54
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile1
-rwxr-xr-xsrc/ci/docker/scripts/build-zstd.sh6
-rw-r--r--src/ci/github-actions/jobs.yml4
-rwxr-xr-xsrc/ci/scripts/free-disk-space.sh142
-rw-r--r--src/doc/rustc-dev-guide/.github/workflows/ci.yml19
-rw-r--r--src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml85
-rw-r--r--src/doc/rustc-dev-guide/.gitignore2
-rw-r--r--src/doc/rustc-dev-guide/README.md7
-rw-r--r--src/doc/rustc-dev-guide/book.toml4
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-driver-example.rs15
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs15
-rw-r--r--src/doc/rustc-dev-guide/josh-sync/src/sync.rs15
-rw-r--r--src/doc/rustc-dev-guide/rust-version2
-rw-r--r--src/doc/rustc-dev-guide/src/appendix/code-index.md3
-rw-r--r--src/doc/rustc-dev-guide/src/appendix/glossary.md2
-rw-r--r--src/doc/rustc-dev-guide/src/backend/backend-agnostic.md2
-rw-r--r--src/doc/rustc-dev-guide/src/borrow_check/region_inference/closure_constraints.md4
-rw-r--r--src/doc/rustc-dev-guide/src/bug-fix-procedure.md2
-rw-r--r--src/doc/rustc-dev-guide/src/closure.md2
-rw-r--r--src/doc/rustc-dev-guide/src/const-eval.md2
-rw-r--r--src/doc/rustc-dev-guide/src/contributing.md62
-rw-r--r--src/doc/rustc-dev-guide/src/conventions.md28
-rw-r--r--src/doc/rustc-dev-guide/src/diagnostics.md2
-rw-r--r--src/doc/rustc-dev-guide/src/external-repos.md6
-rw-r--r--src/doc/rustc-dev-guide/src/guides/editions.md4
-rw-r--r--src/doc/rustc-dev-guide/src/opaque-types-impl-trait-inference.md2
-rw-r--r--src/doc/rustc-dev-guide/src/overview.md4
-rw-r--r--src/doc/rustc-dev-guide/src/rustc-driver/intro.md4
-rw-r--r--src/doc/rustc-dev-guide/src/solve/caching.md4
-rw-r--r--src/doc/rustc-dev-guide/src/solve/invariants.md7
-rw-r--r--src/doc/rustc-dev-guide/src/solve/the-solver.md4
-rw-r--r--src/doc/rustc-dev-guide/src/stability.md3
-rw-r--r--src/doc/rustc-dev-guide/src/tests/ci.md19
-rw-r--r--src/doc/rustc-dev-guide/src/tests/directives.md5
-rw-r--r--src/doc/rustc-dev-guide/src/the-parser.md6
-rw-r--r--src/doc/rustc-dev-guide/src/traits/implied-bounds.md4
-rw-r--r--src/doc/rustc-dev-guide/src/ty_module/binders.md2
-rw-r--r--src/doc/rustc-dev-guide/src/ty_module/early_binder.md2
-rw-r--r--src/doc/rustc-dev-guide/src/ty_module/param_ty_const_regions.md6
-rw-r--r--src/doc/rustc-dev-guide/triagebot.toml3
-rw-r--r--src/doc/rustc/src/platform-support.md5
-rw-r--r--src/doc/rustc/src/platform-support/nuttx.md9
-rw-r--r--src/librustdoc/clean/mod.rs23
-rw-r--r--src/librustdoc/core.rs7
-rw-r--r--src/librustdoc/doctest.rs2
-rw-r--r--src/librustdoc/json/conversions.rs2
-rw-r--r--src/librustdoc/lib.rs17
-rw-r--r--src/librustdoc/visit_ast.rs9
-rw-r--r--src/rustdoc-json-types/lib.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/as_pointer_underscore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/as_underscore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_macros.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_types.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_bits.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_mut.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/op_ref.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/ref_option_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/types/type_complexity.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/types/vec_box.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs7
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs14
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs15
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs6
-rw-r--r--src/tools/clippy/src/driver.rs12
-rw-r--r--src/tools/compiletest/src/common.rs11
-rw-r--r--src/tools/compiletest/src/directive-list.rs1
-rw-r--r--src/tools/compiletest/src/header/needs.rs8
-rw-r--r--src/tools/jsondoclint/src/validator/tests.rs4
-rw-r--r--src/tools/linkchecker/main.rs23
-rw-r--r--src/tools/miri/src/bin/miri.rs25
-rw-r--r--src/tools/tidy/src/ext_tool_checks.rs141
-rw-r--r--src/tools/tidy/src/issues.txt2
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/assembly/powerpc64-struct-abi.rs8
-rw-r--r--tests/assembly/targets/targets-elf.rs15
-rw-r--r--tests/assembly/wasm32-naked-fn.rs199
-rw-r--r--tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff4
-rw-r--r--tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff12
-rw-r--r--tests/mir-opt/coverage/instrument_coverage.rs19
-rw-r--r--tests/rustdoc-json/auxiliary/defines_and_reexports.rs10
-rw-r--r--tests/rustdoc-json/blanket_impls.rs2
-rw-r--r--tests/rustdoc-json/fns/async_return.rs4
-rw-r--r--tests/rustdoc-json/impl-trait-in-assoc-type.rs2
-rw-r--r--tests/rustdoc-json/path_name.rs83
-rw-r--r--tests/rustdoc-json/return_private.rs4
-rw-r--r--tests/rustdoc-json/type/dyn.rs14
-rw-r--r--tests/rustdoc-json/type/generic_default.rs4
-rw-r--r--tests/rustdoc-json/type/hrtb.rs2
-rw-r--r--tests/ui-fulldeps/compiler-calls.rs2
-rw-r--r--tests/ui-fulldeps/obtain-borrowck.rs2
-rw-r--r--tests/ui-fulldeps/run-compiler-twice.rs2
-rw-r--r--tests/ui/abi/homogenous-floats-target-feature-mixup.rs3
-rw-r--r--tests/ui/abi/segfault-no-out-of-stack.rs3
-rw-r--r--tests/ui/abi/stack-probes-lto.rs2
-rw-r--r--tests/ui/abi/stack-probes.rs3
-rw-r--r--tests/ui/alloc-error/default-alloc-error-hook.rs3
-rw-r--r--tests/ui/array-slice-vec/bounds-check-no-overflow.rs2
-rw-r--r--tests/ui/array-slice-vec/box-of-array-of-drop-1.rs4
-rw-r--r--tests/ui/array-slice-vec/box-of-array-of-drop-2.rs4
-rw-r--r--tests/ui/array-slice-vec/dst-raw-slice.rs2
-rw-r--r--tests/ui/array-slice-vec/nested-vec-3.rs4
-rw-r--r--tests/ui/array-slice-vec/slice-panic-1.rs3
-rw-r--r--tests/ui/array-slice-vec/slice-panic-2.rs3
-rw-r--r--tests/ui/array-slice-vec/vec-overrun.rs2
-rw-r--r--tests/ui/associated-types/associated-types-in-ambiguous-context.stderr8
-rw-r--r--tests/ui/async-await/coroutine-desc.stderr1
-rw-r--r--tests/ui/async-await/dont-suggest-missing-await.stderr9
-rw-r--r--tests/ui/backtrace/backtrace.rs3
-rw-r--r--tests/ui/backtrace/std-backtrace.rs3
-rw-r--r--tests/ui/binop/binop-fail-3.rs2
-rw-r--r--tests/ui/binop/binop-panic.rs2
-rw-r--r--tests/ui/borrowck/borrowck-local-borrow.rs2
-rw-r--r--tests/ui/borrowck/issue-28934.rs2
-rw-r--r--tests/ui/box/unit/unwind-unique.rs2
-rw-r--r--tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs2
-rw-r--r--tests/ui/closures/binder/forbid_ambig_const_infers.rs9
-rw-r--r--tests/ui/closures/binder/forbid_ambig_const_infers.stderr10
-rw-r--r--tests/ui/closures/binder/forbid_ambig_type_infers.rs9
-rw-r--r--tests/ui/closures/binder/forbid_ambig_type_infers.stderr10
-rw-r--r--tests/ui/closures/binder/forbid_const_infer.rs7
-rw-r--r--tests/ui/closures/binder/forbid_const_infer.stderr10
-rw-r--r--tests/ui/closures/diverging-closure.rs2
-rw-r--r--tests/ui/command/command-argv0.rs5
-rw-r--r--tests/ui/command/command-current-dir.rs3
-rw-r--r--tests/ui/command/command-exec.rs8
-rw-r--r--tests/ui/command/command-pre-exec.rs10
-rw-r--r--tests/ui/command/command-setgroups.rs5
-rw-r--r--tests/ui/command/command-uid-gid.rs3
-rw-r--r--tests/ui/command/issue-10626.rs3
-rw-r--r--tests/ui/const-generics/generic_arg_infer/parend_infer.rs12
-rw-r--r--tests/ui/const-generics/issues/issue-62878.min.stderr14
-rw-r--r--tests/ui/const-generics/issues/issue-62878.rs2
-rw-r--r--tests/ui/consts/issue-29798.rs2
-rw-r--r--tests/ui/consts/too_generic_eval_ice.stderr10
-rw-r--r--tests/ui/coroutine/coroutine-resume-after-panic.rs2
-rw-r--r--tests/ui/diagnostic-width/secondary-label-with-long-type.rs17
-rw-r--r--tests/ui/diagnostic-width/secondary-label-with-long-type.stderr16
-rw-r--r--tests/ui/did_you_mean/bad-assoc-ty.stderr5
-rw-r--r--tests/ui/drop/drop-order-comparisons.e2021.fixed575
-rw-r--r--tests/ui/drop/drop-order-comparisons.e2021.stderr477
-rw-r--r--tests/ui/drop/drop-order-comparisons.rs575
-rw-r--r--tests/ui/drop/drop-trait-enum.rs2
-rw-r--r--tests/ui/drop/terminate-in-initializer.rs2
-rw-r--r--tests/ui/expr/if/expr-if-panic-fn.rs2
-rw-r--r--tests/ui/expr/if/expr-if-panic.rs2
-rw-r--r--tests/ui/expr/if/if-check-panic.rs2
-rw-r--r--tests/ui/expr/if/if-cond-bot.rs2
-rw-r--r--tests/ui/extern/issue-18576.rs2
-rw-r--r--tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs2
-rw-r--r--tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr15
-rw-r--r--tests/ui/feature-gates/feature-gate-generic_arg_infer.rs6
-rw-r--r--tests/ui/fn/expr-fn-panic.rs2
-rw-r--r--tests/ui/generics/issue-79605.stderr5
-rw-r--r--tests/ui/hashmap/hashmap-capacity-overflow.rs2
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs8
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr32
-rw-r--r--tests/ui/impl-trait/issue-102605.stderr9
-rw-r--r--tests/ui/imports/glob-use-std.rs2
-rw-r--r--tests/ui/inference/issue-72616.stderr13
-rw-r--r--tests/ui/inference/issue-72690.stderr9
-rw-r--r--tests/ui/intrinsics/panic-uninitialized-zeroed.rs9
-rw-r--r--tests/ui/intrinsics/reify-intrinsic.rs6
-rw-r--r--tests/ui/intrinsics/reify-intrinsic.stderr16
-rw-r--r--tests/ui/issues/issue-12920.rs2
-rw-r--r--tests/ui/issues/issue-13202.rs2
-rw-r--r--tests/ui/issues/issue-20971.rs2
-rw-r--r--tests/ui/issues/issue-2190-1.rs14
-rw-r--r--tests/ui/issues/issue-23354-2.rs2
-rw-r--r--tests/ui/issues/issue-23354.rs2
-rw-r--r--tests/ui/issues/issue-2470-bounds-check-overflow.rs2
-rw-r--r--tests/ui/issues/issue-25089.rs2
-rw-r--r--tests/ui/issues/issue-26655.rs2
-rw-r--r--tests/ui/issues/issue-2761.rs2
-rw-r--r--tests/ui/issues/issue-29485.rs2
-rw-r--r--tests/ui/issues/issue-30018-panic.rs2
-rw-r--r--tests/ui/issues/issue-3029.rs2
-rw-r--r--tests/ui/issues/issue-30380.rs2
-rw-r--r--tests/ui/issues/issue-33770.rs3
-rw-r--r--tests/ui/issues/issue-38763.rs2
-rw-r--r--tests/ui/issues/issue-44216-add-system-time.rs2
-rw-r--r--tests/ui/issues/issue-44216-sub-instant.rs2
-rw-r--r--tests/ui/issues/issue-44216-sub-system-time.rs2
-rw-r--r--tests/ui/lifetimes/tail-expr-lock-poisoning.rs3
-rw-r--r--tests/ui/loops/for-each-loop-panic.rs2
-rw-r--r--tests/ui/macros/assert-as-macro.rs2
-rw-r--r--tests/ui/macros/assert-eq-macro-msg.rs2
-rw-r--r--tests/ui/macros/assert-eq-macro-panic.rs2
-rw-r--r--tests/ui/macros/assert-macro-explicit.rs2
-rw-r--r--tests/ui/macros/assert-macro-fmt.rs2
-rw-r--r--tests/ui/macros/assert-macro-owned.rs2
-rw-r--r--tests/ui/macros/assert-macro-static.rs2
-rw-r--r--tests/ui/macros/assert-matches-macro-msg.rs2
-rw-r--r--tests/ui/macros/assert-ne-macro-msg.rs2
-rw-r--r--tests/ui/macros/assert-ne-macro-panic.rs2
-rw-r--r--tests/ui/macros/die-macro-2.rs2
-rw-r--r--tests/ui/macros/die-macro-expr.rs2
-rw-r--r--tests/ui/macros/die-macro-pure.rs2
-rw-r--r--tests/ui/macros/macro-span-issue-116502.stderr7
-rw-r--r--tests/ui/macros/unimplemented-macro-panic.rs2
-rw-r--r--tests/ui/macros/unreachable-arg.rs2
-rw-r--r--tests/ui/macros/unreachable-fmt-msg.rs2
-rw-r--r--tests/ui/macros/unreachable-format-arg.rs2
-rw-r--r--tests/ui/macros/unreachable-format-args.rs2
-rw-r--r--tests/ui/macros/unreachable-macro-panic.rs2
-rw-r--r--tests/ui/macros/unreachable-static-msg.rs2
-rw-r--r--tests/ui/macros/unreachable.rs2
-rw-r--r--tests/ui/match/expr-match-panic-fn.rs2
-rw-r--r--tests/ui/match/expr-match-panic.rs2
-rw-r--r--tests/ui/match/match-bot-panic.rs2
-rw-r--r--tests/ui/match/match-disc-bot.rs2
-rw-r--r--tests/ui/match/match-wildcards.rs2
-rw-r--r--tests/ui/meta/revision-ok.rs2
-rw-r--r--tests/ui/mir/mir_codegen_calls_converging_drops.rs2
-rw-r--r--tests/ui/mir/mir_codegen_calls_converging_drops_2.rs2
-rw-r--r--tests/ui/mir/mir_codegen_calls_diverging.rs2
-rw-r--r--tests/ui/mir/mir_dynamic_drops_1.rs2
-rw-r--r--tests/ui/mir/mir_dynamic_drops_2.rs2
-rw-r--r--tests/ui/mir/mir_dynamic_drops_3.rs2
-rw-r--r--tests/ui/mir/mir_indexing_oob_1.rs2
-rw-r--r--tests/ui/mir/mir_indexing_oob_2.rs2
-rw-r--r--tests/ui/mir/mir_indexing_oob_3.rs2
-rw-r--r--tests/ui/never_type/return-never-coerce.rs2
-rw-r--r--tests/ui/nll/issue-51345-2.rs2
-rw-r--r--tests/ui/numbers-arithmetic/divide-by-zero.rs2
-rw-r--r--tests/ui/numbers-arithmetic/int-abs-overflow.rs2
-rw-r--r--tests/ui/numbers-arithmetic/issue-8460.rs2
-rw-r--r--tests/ui/numbers-arithmetic/mod-zero.rs2
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-add.rs2
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-mul.rs2
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs2
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-pow-signed.rs2
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-pow-unsigned.rs2
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-sub.rs2
-rw-r--r--tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs6
-rw-r--r--tests/ui/panic-runtime/abort.rs6
-rw-r--r--tests/ui/panic-runtime/lto-abort.rs6
-rw-r--r--tests/ui/panic-runtime/lto-unwind.rs7
-rw-r--r--tests/ui/panic-runtime/unwind-interleaved.rs2
-rw-r--r--tests/ui/panic-runtime/unwind-rec.rs2
-rw-r--r--tests/ui/panic-runtime/unwind-rec2.rs2
-rw-r--r--tests/ui/panic-runtime/unwind-unique.rs2
-rw-r--r--tests/ui/panics/abort-on-panic.rs3
-rw-r--r--tests/ui/panics/args-panic.rs2
-rw-r--r--tests/ui/panics/doublepanic.rs2
-rw-r--r--tests/ui/panics/explicit-panic-msg.rs2
-rw-r--r--tests/ui/panics/explicit-panic.rs2
-rw-r--r--tests/ui/panics/fmt-panic.rs2
-rw-r--r--tests/ui/panics/issue-47429-short-backtraces.rs6
-rw-r--r--tests/ui/panics/main-panic.rs2
-rw-r--r--tests/ui/panics/panic-arg.rs2
-rw-r--r--tests/ui/panics/panic-handler-chain-update-hook.rs2
-rw-r--r--tests/ui/panics/panic-handler-flail-wildly.rs2
-rw-r--r--tests/ui/panics/panic-handler-set-twice.rs2
-rw-r--r--tests/ui/panics/panic-in-dtor-drops-fields.rs2
-rw-r--r--tests/ui/panics/panic-macro-any-wrapped.rs2
-rw-r--r--tests/ui/panics/panic-macro-any.rs2
-rw-r--r--tests/ui/panics/panic-macro-explicit.rs2
-rw-r--r--tests/ui/panics/panic-macro-fmt.rs2
-rw-r--r--tests/ui/panics/panic-macro-owned.rs2
-rw-r--r--tests/ui/panics/panic-macro-static.rs2
-rw-r--r--tests/ui/panics/panic-main.rs2
-rw-r--r--tests/ui/panics/panic-parens.rs2
-rw-r--r--tests/ui/panics/panic-recover-propagate.rs2
-rw-r--r--tests/ui/panics/panic-set-handler.rs2
-rw-r--r--tests/ui/panics/panic-set-unset-handler.rs2
-rw-r--r--tests/ui/panics/panic-take-handler-nop.rs2
-rw-r--r--tests/ui/panics/panic.rs2
-rw-r--r--tests/ui/panics/result-get-panic.rs2
-rw-r--r--tests/ui/panics/runtime-switch.rs4
-rw-r--r--tests/ui/panics/test-panic.rs2
-rw-r--r--tests/ui/panics/test-should-panic-no-message.rs2
-rw-r--r--tests/ui/panics/while-body-panics.rs2
-rw-r--r--tests/ui/panics/while-panic.rs2
-rw-r--r--tests/ui/parser/issues/issue-14303-fncall.full.stderr8
-rw-r--r--tests/ui/parser/issues/issue-14303-fncall.generic_arg.stderr8
-rw-r--r--tests/ui/parser/issues/issue-14303-fncall.rs9
-rw-r--r--tests/ui/print-stdout-eprint-stderr.rs3
-rw-r--r--tests/ui/process/core-run-destroy.rs5
-rw-r--r--tests/ui/process/env-args-reverse-iterator.rs3
-rw-r--r--tests/ui/process/fds-are-cloexec.rs5
-rw-r--r--tests/ui/process/inherit-env.rs3
-rw-r--r--tests/ui/process/issue-13304.rs6
-rw-r--r--tests/ui/process/issue-14456.rs6
-rw-r--r--tests/ui/process/issue-14940.rs3
-rw-r--r--tests/ui/process/issue-16272.rs3
-rw-r--r--tests/ui/process/issue-20091.rs6
-rw-r--r--tests/ui/process/issue-30490.rs3
-rw-r--r--tests/ui/process/multi-panic.rs3
-rw-r--r--tests/ui/process/no-stdio.rs3
-rw-r--r--tests/ui/process/println-with-broken-pipe.rs2
-rw-r--r--tests/ui/process/process-envs.rs3
-rw-r--r--tests/ui/process/process-exit.rs6
-rw-r--r--tests/ui/process/process-panic-after-fork.rs5
-rw-r--r--tests/ui/process/process-remove-from-env.rs3
-rw-r--r--tests/ui/process/process-sigpipe.rs2
-rw-r--r--tests/ui/process/process-spawn-nonexistent.rs3
-rw-r--r--tests/ui/process/process-spawn-with-unicode-params.rs3
-rw-r--r--tests/ui/process/process-status-inherits-stdin.rs3
-rw-r--r--tests/ui/process/signal-exit-status.rs5
-rw-r--r--tests/ui/process/sigpipe-should-be-ignored.rs7
-rw-r--r--tests/ui/process/tls-exit-status.rs2
-rw-r--r--tests/ui/process/try-wait.rs6
-rw-r--r--tests/ui/reachable/issue-948.rs2
-rw-r--r--tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error-err.rs2
-rw-r--r--tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-never.rs2
-rw-r--r--tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs2
-rw-r--r--tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str-err.rs2
-rw-r--r--tests/ui/runtime/atomic-print.rs4
-rw-r--r--tests/ui/runtime/backtrace-debuginfo.rs3
-rw-r--r--tests/ui/runtime/out-of-stack.rs3
-rw-r--r--tests/ui/runtime/rt-explody-panic-payloads.rs3
-rw-r--r--tests/ui/runtime/running-with-no-runtime.rs3
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr4
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs.feature.stderr2
-rw-r--r--tests/ui/sepcomp/sepcomp-unwind.rs2
-rw-r--r--tests/ui/simd/target-feature-mixup.rs3
-rw-r--r--tests/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr4
-rw-r--r--tests/ui/std/thread-sleep-ms.rs11
-rw-r--r--tests/ui/stdio-is-blocking.rs3
-rw-r--r--tests/ui/str/str-overrun.rs2
-rw-r--r--tests/ui/structs-enums/unit-like-struct-drop-run.rs2
-rw-r--r--tests/ui/structs/rhs-type.rs2
-rw-r--r--tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs51
-rw-r--r--tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.stderr135
-rw-r--r--tests/ui/suggestions/import-visible-path-39175.fixed16
-rw-r--r--tests/ui/suggestions/import-visible-path-39175.rs (renamed from tests/ui/issues/issue-39175.rs)7
-rw-r--r--tests/ui/suggestions/import-visible-path-39175.stderr (renamed from tests/ui/issues/issue-39175.stderr)6
-rw-r--r--tests/ui/suggestions/issue-109195.rs20
-rw-r--r--tests/ui/suggestions/issue-109195.stderr69
-rw-r--r--tests/ui/test-attrs/terse.rs2
-rw-r--r--tests/ui/test-attrs/test-panic-abort-disabled.rs5
-rw-r--r--tests/ui/test-attrs/test-panic-abort-nocapture.rs6
-rw-r--r--tests/ui/test-attrs/test-panic-abort.rs6
-rw-r--r--tests/ui/test-attrs/test-thread-capture.rs2
-rw-r--r--tests/ui/test-attrs/test-thread-nocapture.rs2
-rw-r--r--tests/ui/threads-sendsync/eprint-on-tls-drop.rs2
-rw-r--r--tests/ui/threads-sendsync/issue-24313.rs2
-rw-r--r--tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs21
-rw-r--r--tests/ui/type-alias-impl-trait/issue-77179.stderr5
-rw-r--r--tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs2
-rw-r--r--tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr4
-rw-r--r--tests/ui/typeck/ice-self-mismatch-const-generics.stderr8
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_item.stderr10
-rw-r--r--tests/ui/wait-forked-but-failed-child.rs3
512 files changed, 6864 insertions, 2124 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c650df6a0ec..7a46d123c5d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -109,7 +109,7 @@ jobs:
       # intensive jobs to run on free runners, which however also have
       # less disk space.
       - name: free up disk space
-        uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
+        run: src/ci/scripts/free-disk-space.sh
         if: matrix.free_disk
 
       # Rust Log Analyzer can't currently detect the PR number of a GitHub
diff --git a/Cargo.lock b/Cargo.lock
index f03b033db6f..10889139e8d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4260,7 +4260,6 @@ dependencies = [
  "rustc_serialize",
  "rustc_type_ir",
  "rustc_type_ir_macros",
- "smallvec",
  "tracing",
 ]
 
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 8e73df63ef5..727fd59c6b3 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};
@@ -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_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 9cfdbc47495..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};
@@ -265,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));
 
@@ -302,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/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/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_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_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_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/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 91283a5944e..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> {
@@ -1178,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/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/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..91b44b084b0 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;
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/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/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/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/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_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 8b666c9100f..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};
 
@@ -60,7 +60,6 @@ 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,
     };
 
@@ -1350,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
@@ -1360,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
@@ -1385,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<'_>| {
@@ -1438,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.
@@ -1583,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_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 5339feb5d27..5075ed86a6a 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)
@@ -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)]
@@ -4537,3 +4647,6 @@ fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Deb
     }
     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/lib.rs b/compiler/rustc_hir/src/lib.rs
index 381062b1429..8ec2054bf53 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -6,6 +6,7 @@
 #![allow(internal_features)]
 #![feature(associated_type_defaults)]
 #![feature(closure_track_caller)]
+#![feature(exhaustive_patterns)]
 #![feature(let_chains)]
 #![feature(never_type)]
 #![feature(rustc_attrs)]
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..dbc5c634c45 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());
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/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 86c6532c97d..c517d25fcbf 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)
                 }
             }
@@ -1453,7 +1436,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..582a2c7a0fc 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;
@@ -489,15 +489,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 +751,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 +812,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 +831,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 +842,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 +853,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 +895,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 +914,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 +1023,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 +1038,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 +1072,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);
                 }
             }
         }
@@ -1983,15 +1987,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 +2313,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 +2421,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/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 5d751a25080..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,6 +9,7 @@ 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, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
@@ -998,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")
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_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/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 e26c09e3601..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()
                     }
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 9cd9ca040ce..c9e55695e5d 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
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/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_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 308d669cf35..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
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index d7370c1ff53..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;
@@ -62,6 +62,8 @@ where
             temps_dir,
         };
 
+        static USING_INTERNAL_FEATURES: AtomicBool = AtomicBool::new(false);
+
         let sess = build_session(
             early_dcx,
             sessopts,
@@ -74,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/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/lints.rs b/compiler/rustc_lint/src/lints.rs
index 2f610802ff5..84a6272198f 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;
@@ -293,7 +294,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
diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index a1cc3a85109..1bf19047ade 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);
                 }
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..244cd358e9c 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()) {
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 0757e6840c6..0060f33888e 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -4,7 +4,8 @@ use std::ops::ControlFlow;
 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::{
@@ -1526,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)
@@ -1554,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()
     }
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/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/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/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/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 65e93c3a1cc..17e1fe35bba 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;
 
@@ -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
     }
@@ -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/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 2d76f6ec7d6..aeb734ba3f6 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;
@@ -2028,7 +2028,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
     }
 
@@ -2050,7 +2050,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,
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index e4187d2760c..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::*;
 
@@ -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/values.rs b/compiler/rustc_middle/src/values.rs
index 9120a248d95..867f8f63969 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -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_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 8d397f63cc7..50ebde3292e 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -11,7 +11,9 @@ use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId,
 
 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;
@@ -27,12 +29,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 +42,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 +83,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/node_flow.rs b/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs
index 610498c6c0e..3647c889937 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,17 @@
 
 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 +29,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 +41,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 +132,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 +148,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 +184,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 +226,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 +259,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 +270,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 +279,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/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 19568735df7..b8aa76a7dbe 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -180,7 +180,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 +211,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_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/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/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 10756be6afb..25d8eb9b453 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.
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 9a3e79c16b4..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
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index dbb87443eed..576ca24bf99 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -2808,7 +2808,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 34deb854e0f..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)
                             {
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/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_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index cb7b0815a49..d19df08519d 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -27,8 +27,8 @@ 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 _;
@@ -1179,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(
@@ -1195,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;
@@ -1208,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_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 60f1154dc6d..10f1ce376ef 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
@@ -966,7 +966,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
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_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 1f2df7f0168..37564ab38fc 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),
 
@@ -1971,6 +1974,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_nuttx.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs
new file mode 100644
index 00000000000..04fd3ec1c26
--- /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(false),
+        },
+        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..138716e8f14
--- /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(false),
+        },
+        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..40391c9f48e
--- /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(false),
+        },
+        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/thumbv7a_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs
new file mode 100644
index 00000000000..7fd22602e56
--- /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: None,
+            host_tools: None,
+            std: None,
+        },
+        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..d3148c53a82
--- /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: None,
+            host_tools: None,
+            std: None,
+        },
+        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_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 1e9ef5e536c..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);
     }
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 503090b5797..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(),
@@ -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 bcd3b0109b7..961719f263c 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
@@ -580,8 +580,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
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 f2bcc51e687..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);
         }
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 4669d286665..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}");
@@ -3074,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.
@@ -5065,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())
@@ -5073,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);
     }
@@ -5187,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), .. },
@@ -5480,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 0bf91ad35c1..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;
             }
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_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_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/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs
new file mode 100644
index 00000000000..61e61019b50
--- /dev/null
+++ b/library/alloc/src/bstr.rs
@@ -0,0 +1,702 @@
+//! The `ByteStr` and `ByteString` types and trait implementations.
+
+// This could be more fine-grained.
+#![cfg(not(no_global_oom_handling))]
+
+use core::borrow::{Borrow, BorrowMut};
+#[unstable(feature = "bstr", issue = "134915")]
+pub use core::bstr::ByteStr;
+use core::bstr::{impl_partial_eq, impl_partial_eq_n, impl_partial_eq_ord};
+use core::cmp::Ordering;
+use core::ops::{
+    Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive,
+    RangeTo, RangeToInclusive,
+};
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+use core::str::FromStr;
+use core::{fmt, hash};
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+use crate::borrow::{Cow, ToOwned};
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+use crate::boxed::Box;
+#[cfg(not(no_rc))]
+use crate::rc::Rc;
+use crate::string::String;
+#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
+use crate::sync::Arc;
+use crate::vec::Vec;
+
+/// A wrapper for `Vec<u8>` representing a human-readable string that's conventionally, but not
+/// always, UTF-8.
+///
+/// Unlike `String`, this type permits non-UTF-8 contents, making it suitable for user input,
+/// non-native filenames (as `Path` only supports native filenames), and other applications that
+/// need to round-trip whatever data the user provides.
+///
+/// A `ByteString` owns its contents and can grow and shrink, like a `Vec` or `String`. For a
+/// borrowed byte string, see [`ByteStr`](../../std/bstr/struct.ByteStr.html).
+///
+/// `ByteString` implements `Deref` to `&Vec<u8>`, so all methods available on `&Vec<u8>` are
+/// available on `ByteString`. Similarly, `ByteString` implements `DerefMut` to `&mut Vec<u8>`,
+/// so you can modify a `ByteString` using any method available on `&mut Vec<u8>`.
+///
+/// The `Debug` and `Display` implementations for `ByteString` are the same as those for `ByteStr`,
+/// showing invalid UTF-8 as hex escapes or the Unicode replacement character, respectively.
+#[unstable(feature = "bstr", issue = "134915")]
+#[repr(transparent)]
+#[derive(Clone)]
+#[doc(alias = "BString")]
+pub struct ByteString(pub Vec<u8>);
+
+impl ByteString {
+    #[inline]
+    pub(crate) fn as_bytes(&self) -> &[u8] {
+        &self.0
+    }
+
+    #[inline]
+    pub(crate) fn as_bytestr(&self) -> &ByteStr {
+        ByteStr::new(&self.0)
+    }
+
+    #[inline]
+    pub(crate) fn as_mut_bytestr(&mut self) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Deref for ByteString {
+    type Target = Vec<u8>;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl DerefMut for ByteString {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+#[unstable(feature = "deref_pure_trait", issue = "87121")]
+unsafe impl DerefPure for ByteString {}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl fmt::Debug for ByteString {
+    #[inline]
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(self.as_bytestr(), f)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl fmt::Display for ByteString {
+    #[inline]
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self.as_bytestr(), f)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsRef<[u8]> for ByteString {
+    #[inline]
+    fn as_ref(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsRef<ByteStr> for ByteString {
+    #[inline]
+    fn as_ref(&self) -> &ByteStr {
+        self.as_bytestr()
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsMut<[u8]> for ByteString {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [u8] {
+        &mut self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsMut<ByteStr> for ByteString {
+    #[inline]
+    fn as_mut(&mut self) -> &mut ByteStr {
+        self.as_mut_bytestr()
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Borrow<[u8]> for ByteString {
+    #[inline]
+    fn borrow(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Borrow<ByteStr> for ByteString {
+    #[inline]
+    fn borrow(&self) -> &ByteStr {
+        self.as_bytestr()
+    }
+}
+
+// `impl Borrow<ByteStr> for Vec<u8>` omitted to avoid inference failures
+// `impl Borrow<ByteStr> for String` omitted to avoid inference failures
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl BorrowMut<[u8]> for ByteString {
+    #[inline]
+    fn borrow_mut(&mut self) -> &mut [u8] {
+        &mut self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl BorrowMut<ByteStr> for ByteString {
+    #[inline]
+    fn borrow_mut(&mut self) -> &mut ByteStr {
+        self.as_mut_bytestr()
+    }
+}
+
+// `impl BorrowMut<ByteStr> for Vec<u8>` omitted to avoid inference failures
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Default for ByteString {
+    fn default() -> Self {
+        ByteString(Vec::new())
+    }
+}
+
+// Omitted due to inference failures
+//
+// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a, const N: usize> From<&'a [u8; N]> for ByteString {
+//     #[inline]
+//     fn from(s: &'a [u8; N]) -> Self {
+//         ByteString(s.as_slice().to_vec())
+//     }
+// }
+//
+// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<const N: usize> From<[u8; N]> for ByteString {
+//     #[inline]
+//     fn from(s: [u8; N]) -> Self {
+//         ByteString(s.as_slice().to_vec())
+//     }
+// }
+//
+// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a> From<&'a [u8]> for ByteString {
+//     #[inline]
+//     fn from(s: &'a [u8]) -> Self {
+//         ByteString(s.to_vec())
+//     }
+// }
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl From<Vec<u8>> for ByteString {
+//     #[inline]
+//     fn from(s: Vec<u8>) -> Self {
+//         ByteString(s)
+//     }
+// }
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl From<ByteString> for Vec<u8> {
+    #[inline]
+    fn from(s: ByteString) -> Self {
+        s.0
+    }
+}
+
+// Omitted due to inference failures
+//
+// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a> From<&'a str> for ByteString {
+//     #[inline]
+//     fn from(s: &'a str) -> Self {
+//         ByteString(s.as_bytes().to_vec())
+//     }
+// }
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl From<String> for ByteString {
+//     #[inline]
+//     fn from(s: String) -> Self {
+//         ByteString(s.into_bytes())
+//     }
+// }
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> From<&'a ByteStr> for ByteString {
+    #[inline]
+    fn from(s: &'a ByteStr) -> Self {
+        ByteString(s.0.to_vec())
+    }
+}
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> From<ByteString> for Cow<'a, ByteStr> {
+    #[inline]
+    fn from(s: ByteString) -> Self {
+        Cow::Owned(s)
+    }
+}
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> {
+    #[inline]
+    fn from(s: &'a ByteString) -> Self {
+        Cow::Borrowed(s.as_bytestr())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl FromIterator<char> for ByteString {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
+        ByteString(iter.into_iter().collect::<String>().into_bytes())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl FromIterator<u8> for ByteString {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
+        ByteString(iter.into_iter().collect())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> FromIterator<&'a str> for ByteString {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
+        ByteString(iter.into_iter().collect::<String>().into_bytes())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> FromIterator<&'a [u8]> for ByteString {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = &'a [u8]>>(iter: T) -> Self {
+        let mut buf = Vec::new();
+        for b in iter {
+            buf.extend_from_slice(b);
+        }
+        ByteString(buf)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> FromIterator<&'a ByteStr> for ByteString {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = &'a ByteStr>>(iter: T) -> Self {
+        let mut buf = Vec::new();
+        for b in iter {
+            buf.extend_from_slice(&b.0);
+        }
+        ByteString(buf)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl FromIterator<ByteString> for ByteString {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = ByteString>>(iter: T) -> Self {
+        let mut buf = Vec::new();
+        for mut b in iter {
+            buf.append(&mut b.0);
+        }
+        ByteString(buf)
+    }
+}
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+#[unstable(feature = "bstr", issue = "134915")]
+impl FromStr for ByteString {
+    type Err = core::convert::Infallible;
+
+    #[inline]
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Ok(ByteString(s.as_bytes().to_vec()))
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<usize> for ByteString {
+    type Output = u8;
+
+    #[inline]
+    fn index(&self, idx: usize) -> &u8 {
+        &self.0[idx]
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeFull> for ByteString {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, _: RangeFull) -> &ByteStr {
+        self.as_bytestr()
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<Range<usize>> for ByteString {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: Range<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeInclusive<usize>> for ByteString {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeInclusive<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeFrom<usize>> for ByteString {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeFrom<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeTo<usize>> for ByteString {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeTo<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeToInclusive<usize>> for ByteString {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeToInclusive<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<usize> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, idx: usize) -> &mut u8 {
+        &mut self.0[idx]
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeFull> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr {
+        self.as_mut_bytestr()
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<Range<usize>> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, r: Range<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeInclusive<usize>> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, r: RangeInclusive<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeFrom<usize>> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, r: RangeFrom<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeTo<usize>> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, r: RangeTo<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeToInclusive<usize>> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, r: RangeToInclusive<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl hash::Hash for ByteString {
+    #[inline]
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        self.0.hash(state);
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Eq for ByteString {}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl PartialEq for ByteString {
+    #[inline]
+    fn eq(&self, other: &ByteString) -> bool {
+        self.0 == other.0
+    }
+}
+
+macro_rules! impl_partial_eq_ord_cow {
+    ($lhs:ty, $rhs:ty) => {
+        #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+        #[allow(unused_lifetimes)]
+        #[unstable(feature = "bstr", issue = "134915")]
+        impl<'a> PartialEq<$rhs> for $lhs {
+            #[inline]
+            fn eq(&self, other: &$rhs) -> bool {
+                let other: &[u8] = (&**other).as_ref();
+                PartialEq::eq(self.as_bytes(), other)
+            }
+        }
+
+        #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+        #[allow(unused_lifetimes)]
+        #[unstable(feature = "bstr", issue = "134915")]
+        impl<'a> PartialEq<$lhs> for $rhs {
+            #[inline]
+            fn eq(&self, other: &$lhs) -> bool {
+                let this: &[u8] = (&**self).as_ref();
+                PartialEq::eq(this, other.as_bytes())
+            }
+        }
+
+        #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+        #[allow(unused_lifetimes)]
+        #[unstable(feature = "bstr", issue = "134915")]
+        impl<'a> PartialOrd<$rhs> for $lhs {
+            #[inline]
+            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
+                let other: &[u8] = (&**other).as_ref();
+                PartialOrd::partial_cmp(self.as_bytes(), other)
+            }
+        }
+
+        #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+        #[allow(unused_lifetimes)]
+        #[unstable(feature = "bstr", issue = "134915")]
+        impl<'a> PartialOrd<$lhs> for $rhs {
+            #[inline]
+            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
+                let this: &[u8] = (&**self).as_ref();
+                PartialOrd::partial_cmp(this, other.as_bytes())
+            }
+        }
+    };
+}
+
+// PartialOrd with `Vec<u8>` omitted to avoid inference failures
+impl_partial_eq!(ByteString, Vec<u8>);
+// PartialOrd with `[u8]` omitted to avoid inference failures
+impl_partial_eq!(ByteString, [u8]);
+// PartialOrd with `&[u8]` omitted to avoid inference failures
+impl_partial_eq!(ByteString, &[u8]);
+// PartialOrd with `String` omitted to avoid inference failures
+impl_partial_eq!(ByteString, String);
+// PartialOrd with `str` omitted to avoid inference failures
+impl_partial_eq!(ByteString, str);
+// PartialOrd with `&str` omitted to avoid inference failures
+impl_partial_eq!(ByteString, &str);
+impl_partial_eq_ord!(ByteString, ByteStr);
+impl_partial_eq_ord!(ByteString, &ByteStr);
+// PartialOrd with `[u8; N]` omitted to avoid inference failures
+impl_partial_eq_n!(ByteString, [u8; N]);
+// PartialOrd with `&[u8; N]` omitted to avoid inference failures
+impl_partial_eq_n!(ByteString, &[u8; N]);
+impl_partial_eq_ord_cow!(ByteString, Cow<'_, ByteStr>);
+impl_partial_eq_ord_cow!(ByteString, Cow<'_, str>);
+impl_partial_eq_ord_cow!(ByteString, Cow<'_, [u8]>);
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Ord for ByteString {
+    #[inline]
+    fn cmp(&self, other: &ByteString) -> Ordering {
+        Ord::cmp(&self.0, &other.0)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl PartialOrd for ByteString {
+    #[inline]
+    fn partial_cmp(&self, other: &ByteString) -> Option<Ordering> {
+        PartialOrd::partial_cmp(&self.0, &other.0)
+    }
+}
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+#[unstable(feature = "bstr", issue = "134915")]
+impl ToOwned for ByteStr {
+    type Owned = ByteString;
+
+    #[inline]
+    fn to_owned(&self) -> ByteString {
+        ByteString(self.0.to_vec())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl TryFrom<ByteString> for String {
+    type Error = crate::string::FromUtf8Error;
+
+    #[inline]
+    fn try_from(s: ByteString) -> Result<Self, Self::Error> {
+        String::from_utf8(s.0)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> TryFrom<&'a ByteString> for &'a str {
+    type Error = crate::str::Utf8Error;
+
+    #[inline]
+    fn try_from(s: &'a ByteString) -> Result<Self, Self::Error> {
+        crate::str::from_utf8(s.0.as_slice())
+    }
+}
+
+// Additional impls for `ByteStr` that require types from `alloc`:
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+#[unstable(feature = "bstr", issue = "134915")]
+impl Clone for Box<ByteStr> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::from(Box::<[u8]>::from(&self.0))
+    }
+}
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> {
+    #[inline]
+    fn from(s: &'a ByteStr) -> Self {
+        Cow::Borrowed(s)
+    }
+}
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+#[unstable(feature = "bstr", issue = "134915")]
+impl From<Box<[u8]>> for Box<ByteStr> {
+    #[inline]
+    fn from(s: Box<[u8]>) -> Box<ByteStr> {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
+        unsafe { Box::from_raw(Box::into_raw(s) as _) }
+    }
+}
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+#[unstable(feature = "bstr", issue = "134915")]
+impl From<Box<ByteStr>> for Box<[u8]> {
+    #[inline]
+    fn from(s: Box<ByteStr>) -> Box<[u8]> {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
+        unsafe { Box::from_raw(Box::into_raw(s) as _) }
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+#[cfg(not(no_rc))]
+impl From<Rc<[u8]>> for Rc<ByteStr> {
+    #[inline]
+    fn from(s: Rc<[u8]>) -> Rc<ByteStr> {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
+        unsafe { Rc::from_raw(Rc::into_raw(s) as _) }
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+#[cfg(not(no_rc))]
+impl From<Rc<ByteStr>> for Rc<[u8]> {
+    #[inline]
+    fn from(s: Rc<ByteStr>) -> Rc<[u8]> {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
+        unsafe { Rc::from_raw(Rc::into_raw(s) as _) }
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
+impl From<Arc<[u8]>> for Arc<ByteStr> {
+    #[inline]
+    fn from(s: Arc<[u8]>) -> Arc<ByteStr> {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
+        unsafe { Arc::from_raw(Arc::into_raw(s) as _) }
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
+impl From<Arc<ByteStr>> for Arc<[u8]> {
+    #[inline]
+    fn from(s: Arc<ByteStr>) -> Arc<[u8]> {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
+        unsafe { Arc::from_raw(Arc::into_raw(s) as _) }
+    }
+}
+
+// PartialOrd with `Vec<u8>` omitted to avoid inference failures
+impl_partial_eq!(ByteStr, Vec<u8>);
+// PartialOrd with `String` omitted to avoid inference failures
+impl_partial_eq!(ByteStr, String);
+impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, ByteStr>);
+impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, str>);
+impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, [u8]>);
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> TryFrom<&'a ByteStr> for String {
+    type Error = core::str::Utf8Error;
+
+    #[inline]
+    fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> {
+        Ok(core::str::from_utf8(&s.0)?.into())
+    }
+}
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 0b6a55297e1..1c33f8f60d8 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -1735,6 +1735,52 @@ impl<T, A: Allocator> VecDeque<T, A> {
         }
     }
 
+    /// Removes and returns the first element from the deque if the predicate
+    /// returns `true`, or [`None`] if the predicate returns false or the deque
+    /// is empty (the predicate will not be called in that case).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_deque_pop_if)]
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut deque: VecDeque<i32> = vec![0, 1, 2, 3, 4].into();
+    /// let pred = |x: &mut i32| *x % 2 == 0;
+    ///
+    /// assert_eq!(deque.pop_front_if(pred), Some(0));
+    /// assert_eq!(deque, [1, 2, 3, 4]);
+    /// assert_eq!(deque.pop_front_if(pred), None);
+    /// ```
+    #[unstable(feature = "vec_deque_pop_if", issue = "135889")]
+    pub fn pop_front_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option<T> {
+        let first = self.front_mut()?;
+        if predicate(first) { self.pop_front() } else { None }
+    }
+
+    /// Removes and returns the last element from the deque if the predicate
+    /// returns `true`, or [`None`] if the predicate returns false or the deque
+    /// is empty (the predicate will not be called in that case).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_deque_pop_if)]
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut deque: VecDeque<i32> = vec![0, 1, 2, 3, 4].into();
+    /// let pred = |x: &mut i32| *x % 2 == 0;
+    ///
+    /// assert_eq!(deque.pop_back_if(pred), Some(4));
+    /// assert_eq!(deque, [0, 1, 2, 3]);
+    /// assert_eq!(deque.pop_back_if(pred), None);
+    /// ```
+    #[unstable(feature = "vec_deque_pop_if", issue = "135889")]
+    pub fn pop_back_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option<T> {
+        let first = self.back_mut()?;
+        if predicate(first) { self.pop_back() } else { None }
+    }
+
     /// Prepends an element to the deque.
     ///
     /// # Examples
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index b4f08debc93..28e4217e303 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -102,6 +102,8 @@
 #![feature(async_fn_traits)]
 #![feature(async_iterator)]
 #![feature(box_uninit_write)]
+#![feature(bstr)]
+#![feature(bstr_internals)]
 #![feature(clone_to_uninit)]
 #![feature(coerce_unsized)]
 #![feature(const_eval_select)]
@@ -228,6 +230,8 @@ mod boxed {
     pub use std::boxed::Box;
 }
 pub mod borrow;
+#[unstable(feature = "bstr", issue = "134915")]
+pub mod bstr;
 pub mod collections;
 #[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))]
 pub mod ffi;
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index cd2afd7a473..54673ceb1da 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2511,9 +2511,9 @@ impl<T, A: Allocator> Vec<T, A> {
         }
     }
 
-    /// Removes and returns the last element in a vector if the predicate
+    /// Removes and returns the last element from a vector if the predicate
     /// returns `true`, or [`None`] if the predicate returns false or the vector
-    /// is empty.
+    /// is empty (the predicate will not be called in that case).
     ///
     /// # Examples
     ///
@@ -2528,12 +2528,9 @@ impl<T, A: Allocator> Vec<T, A> {
     /// assert_eq!(vec.pop_if(pred), None);
     /// ```
     #[unstable(feature = "vec_pop_if", issue = "122741")]
-    pub fn pop_if<F>(&mut self, f: F) -> Option<T>
-    where
-        F: FnOnce(&mut T) -> bool,
-    {
+    pub fn pop_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option<T> {
         let last = self.last_mut()?;
-        if f(last) { self.pop() } else { None }
+        if predicate(last) { self.pop() } else { None }
     }
 
     /// Moves all the elements of `other` into `self`, leaving `other` empty.
@@ -2574,9 +2571,11 @@ impl<T, A: Allocator> Vec<T, A> {
         self.len += count;
     }
 
-    /// Removes the specified range from the vector in bulk, returning all
-    /// removed elements as an iterator. If the iterator is dropped before
-    /// being fully consumed, it drops the remaining removed elements.
+    /// Removes the subslice indicated by the given range from the vector,
+    /// returning a double-ended iterator over the removed subslice.
+    ///
+    /// If the iterator is dropped before being fully consumed,
+    /// it drops the remaining removed elements.
     ///
     /// The returned iterator keeps a mutable borrow on the vector to optimize
     /// its implementation.
@@ -3016,10 +3015,9 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
     /// Iterates over the slice `other`, clones each element, and then appends
     /// it to this `Vec`. The `other` slice is traversed in-order.
     ///
-    /// Note that this function is same as [`extend`] except that it is
-    /// specialized to work with slices instead. If and when Rust gets
-    /// specialization this function will likely be deprecated (but still
-    /// available).
+    /// Note that this function is the same as [`extend`],
+    /// except that it also works with slice elements that are Clone but not Copy.
+    /// If Rust gets specialization this function may be deprecated.
     ///
     /// # Examples
     ///
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 393bdfe48b7..d8364d750fa 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -38,6 +38,7 @@
 #![feature(str_as_str)]
 #![feature(strict_provenance_lints)]
 #![feature(vec_pop_if)]
+#![feature(vec_deque_pop_if)]
 #![feature(unique_rc_arc)]
 #![feature(macro_metavar_expr_concat)]
 #![allow(internal_features)]
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs
index 4b8d3c735f7..1b03c29e5bd 100644
--- a/library/alloc/tests/vec_deque.rs
+++ b/library/alloc/tests/vec_deque.rs
@@ -81,6 +81,45 @@ fn test_parameterized<T: Clone + PartialEq + Debug>(a: T, b: T, c: T, d: T) {
 }
 
 #[test]
+fn test_pop_if() {
+    let mut deq: VecDeque<_> = vec![0, 1, 2, 3, 4].into();
+    let pred = |x: &mut i32| *x % 2 == 0;
+
+    assert_eq!(deq.pop_front_if(pred), Some(0));
+    assert_eq!(deq, [1, 2, 3, 4]);
+
+    assert_eq!(deq.pop_front_if(pred), None);
+    assert_eq!(deq, [1, 2, 3, 4]);
+
+    assert_eq!(deq.pop_back_if(pred), Some(4));
+    assert_eq!(deq, [1, 2, 3]);
+
+    assert_eq!(deq.pop_back_if(pred), None);
+    assert_eq!(deq, [1, 2, 3]);
+}
+
+#[test]
+fn test_pop_if_empty() {
+    let mut deq = VecDeque::<i32>::new();
+    assert_eq!(deq.pop_front_if(|_| true), None);
+    assert_eq!(deq.pop_back_if(|_| true), None);
+    assert!(deq.is_empty());
+}
+
+#[test]
+fn test_pop_if_mutates() {
+    let mut v: VecDeque<_> = vec![-1, 1].into();
+    let pred = |x: &mut i32| {
+        *x *= 2;
+        false
+    };
+    assert_eq!(v.pop_front_if(pred), None);
+    assert_eq!(v, [-2, 1]);
+    assert_eq!(v.pop_back_if(pred), None);
+    assert_eq!(v, [-2, 2]);
+}
+
+#[test]
 fn test_push_front_grow() {
     let mut deq = VecDeque::new();
     for i in 0..66 {
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index ba61679564a..28329bb0908 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -156,7 +156,6 @@ pub const fn from_mut<T>(s: &mut T) -> &mut [T; 1] {
 
 /// The error type returned when a conversion from a slice to an array fails.
 #[stable(feature = "try_from", since = "1.34.0")]
-#[rustc_allowed_through_unstable_modules]
 #[derive(Debug, Copy, Clone)]
 pub struct TryFromSliceError(());
 
diff --git a/library/core/src/bstr.rs b/library/core/src/bstr.rs
new file mode 100644
index 00000000000..74e07f3d242
--- /dev/null
+++ b/library/core/src/bstr.rs
@@ -0,0 +1,581 @@
+//! The `ByteStr` type and trait implementations.
+
+use crate::borrow::{Borrow, BorrowMut};
+use crate::cmp::Ordering;
+use crate::ops::{
+    Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive,
+    RangeTo, RangeToInclusive,
+};
+use crate::{fmt, hash};
+
+/// A wrapper for `&[u8]` representing a human-readable string that's conventionally, but not
+/// always, UTF-8.
+///
+/// Unlike `&str`, this type permits non-UTF-8 contents, making it suitable for user input,
+/// non-native filenames (as `Path` only supports native filenames), and other applications that
+/// need to round-trip whatever data the user provides.
+///
+/// For an owned, growable byte string buffer, use
+/// [`ByteString`](../../std/bstr/struct.ByteString.html).
+///
+/// `ByteStr` implements `Deref` to `[u8]`, so all methods available on `[u8]` are available on
+/// `ByteStr`.
+///
+/// # Representation
+///
+/// A `&ByteStr` has the same representation as a `&str`. That is, a `&ByteStr` is a wide pointer
+/// which includes a pointer to some bytes and a length.
+///
+/// # Trait implementations
+///
+/// The `ByteStr` type has a number of trait implementations, and in particular, defines equality
+/// and comparisons between `&ByteStr`, `&str`, and `&[u8]`, for convenience.
+///
+/// The `Debug` implementation for `ByteStr` shows its bytes as a normal string, with invalid UTF-8
+/// presented as hex escape sequences.
+///
+/// The `Display` implementation behaves as if the `ByteStr` were first lossily converted to a
+/// `str`, with invalid UTF-8 presented as the Unicode replacement character: �
+///
+#[unstable(feature = "bstr", issue = "134915")]
+#[repr(transparent)]
+#[doc(alias = "BStr")]
+pub struct ByteStr(pub [u8]);
+
+impl ByteStr {
+    /// Creates a `ByteStr` slice from anything that can be converted to a byte slice.
+    ///
+    /// This is a zero-cost conversion.
+    ///
+    /// # Example
+    ///
+    /// You can create a `ByteStr` from a byte array, a byte slice or a string slice:
+    ///
+    /// ```
+    /// # #![feature(bstr)]
+    /// # use std::bstr::ByteStr;
+    /// let a = ByteStr::new(b"abc");
+    /// let b = ByteStr::new(&b"abc"[..]);
+    /// let c = ByteStr::new("abc");
+    ///
+    /// assert_eq!(a, b);
+    /// assert_eq!(a, c);
+    /// ```
+    #[inline]
+    #[unstable(feature = "bstr", issue = "134915")]
+    pub fn new<B: ?Sized + AsRef<[u8]>>(bytes: &B) -> &Self {
+        ByteStr::from_bytes(bytes.as_ref())
+    }
+
+    #[doc(hidden)]
+    #[unstable(feature = "bstr_internals", issue = "none")]
+    #[inline]
+    pub fn from_bytes(slice: &[u8]) -> &Self {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to
+        // the wrapped type into a reference to the wrapper type.
+        unsafe { &*(slice as *const [u8] as *const Self) }
+    }
+
+    #[doc(hidden)]
+    #[unstable(feature = "bstr_internals", issue = "none")]
+    #[inline]
+    pub fn from_bytes_mut(slice: &mut [u8]) -> &mut Self {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to
+        // the wrapped type into a reference to the wrapper type.
+        unsafe { &mut *(slice as *mut [u8] as *mut Self) }
+    }
+
+    #[doc(hidden)]
+    #[unstable(feature = "bstr_internals", issue = "none")]
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Deref for ByteStr {
+    type Target = [u8];
+
+    #[inline]
+    fn deref(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl DerefMut for ByteStr {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut [u8] {
+        &mut self.0
+    }
+}
+
+#[unstable(feature = "deref_pure_trait", issue = "87121")]
+unsafe impl DerefPure for ByteStr {}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl fmt::Debug for ByteStr {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "\"")?;
+        for chunk in self.utf8_chunks() {
+            for c in chunk.valid().chars() {
+                match c {
+                    '\0' => write!(f, "\\0")?,
+                    '\x01'..='\x7f' => write!(f, "{}", (c as u8).escape_ascii())?,
+                    _ => write!(f, "{}", c.escape_debug())?,
+                }
+            }
+            write!(f, "{}", chunk.invalid().escape_ascii())?;
+        }
+        write!(f, "\"")?;
+        Ok(())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl fmt::Display for ByteStr {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fn fmt_nopad(this: &ByteStr, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            for chunk in this.utf8_chunks() {
+                f.write_str(chunk.valid())?;
+                if !chunk.invalid().is_empty() {
+                    f.write_str("\u{FFFD}")?;
+                }
+            }
+            Ok(())
+        }
+
+        let Some(align) = f.align() else {
+            return fmt_nopad(self, f);
+        };
+        let nchars: usize = self
+            .utf8_chunks()
+            .map(|chunk| chunk.valid().len() + if chunk.invalid().is_empty() { 0 } else { 1 })
+            .sum();
+        let padding = f.width().unwrap_or(0).saturating_sub(nchars);
+        let fill = f.fill();
+        let (lpad, rpad) = match align {
+            fmt::Alignment::Left => (0, padding),
+            fmt::Alignment::Right => (padding, 0),
+            fmt::Alignment::Center => {
+                let half = padding / 2;
+                (half, half + padding % 2)
+            }
+        };
+        for _ in 0..lpad {
+            write!(f, "{fill}")?;
+        }
+        fmt_nopad(self, f)?;
+        for _ in 0..rpad {
+            write!(f, "{fill}")?;
+        }
+
+        Ok(())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsRef<[u8]> for ByteStr {
+    #[inline]
+    fn as_ref(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsRef<ByteStr> for ByteStr {
+    #[inline]
+    fn as_ref(&self) -> &ByteStr {
+        self
+    }
+}
+
+// `impl AsRef<ByteStr> for [u8]` omitted to avoid widespread inference failures
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsRef<ByteStr> for str {
+    #[inline]
+    fn as_ref(&self) -> &ByteStr {
+        ByteStr::new(self)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsMut<[u8]> for ByteStr {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [u8] {
+        &mut self.0
+    }
+}
+
+// `impl AsMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
+
+// `impl Borrow<ByteStr> for [u8]` omitted to avoid widespread inference failures
+
+// `impl Borrow<ByteStr> for str` omitted to avoid widespread inference failures
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Borrow<[u8]> for ByteStr {
+    #[inline]
+    fn borrow(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+// `impl BorrowMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl BorrowMut<[u8]> for ByteStr {
+    #[inline]
+    fn borrow_mut(&mut self) -> &mut [u8] {
+        &mut self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> Default for &'a ByteStr {
+    fn default() -> Self {
+        ByteStr::from_bytes(b"")
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> Default for &'a mut ByteStr {
+    fn default() -> Self {
+        ByteStr::from_bytes_mut(&mut [])
+    }
+}
+
+// Omitted due to inference failures
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr {
+//     #[inline]
+//     fn from(s: &'a [u8; N]) -> Self {
+//         ByteStr::from_bytes(s)
+//     }
+// }
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a> From<&'a [u8]> for &'a ByteStr {
+//     #[inline]
+//     fn from(s: &'a [u8]) -> Self {
+//         ByteStr::from_bytes(s)
+//     }
+// }
+
+// Omitted due to slice-from-array-issue-113238:
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a> From<&'a ByteStr> for &'a [u8] {
+//     #[inline]
+//     fn from(s: &'a ByteStr) -> Self {
+//         &s.0
+//     }
+// }
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a> From<&'a mut ByteStr> for &'a mut [u8] {
+//     #[inline]
+//     fn from(s: &'a mut ByteStr) -> Self {
+//         &mut s.0
+//     }
+// }
+
+// Omitted due to inference failures
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a> From<&'a str> for &'a ByteStr {
+//     #[inline]
+//     fn from(s: &'a str) -> Self {
+//         ByteStr::from_bytes(s.as_bytes())
+//     }
+// }
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl hash::Hash for ByteStr {
+    #[inline]
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        self.0.hash(state);
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<usize> for ByteStr {
+    type Output = u8;
+
+    #[inline]
+    fn index(&self, idx: usize) -> &u8 {
+        &self.0[idx]
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeFull> for ByteStr {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, _: RangeFull) -> &ByteStr {
+        self
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<Range<usize>> for ByteStr {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: Range<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeInclusive<usize>> for ByteStr {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeInclusive<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeFrom<usize>> for ByteStr {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeFrom<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeTo<usize>> for ByteStr {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeTo<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeToInclusive<usize>> for ByteStr {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeToInclusive<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<usize> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, idx: usize) -> &mut u8 {
+        &mut self.0[idx]
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeFull> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr {
+        self
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<Range<usize>> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, r: Range<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeInclusive<usize>> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, r: RangeInclusive<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeFrom<usize>> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, r: RangeFrom<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeTo<usize>> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, r: RangeTo<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeToInclusive<usize>> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, r: RangeToInclusive<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Eq for ByteStr {}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl PartialEq<ByteStr> for ByteStr {
+    #[inline]
+    fn eq(&self, other: &ByteStr) -> bool {
+        &self.0 == &other.0
+    }
+}
+
+#[doc(hidden)]
+#[macro_export]
+#[unstable(feature = "bstr_internals", issue = "none")]
+macro_rules! impl_partial_eq {
+    ($lhs:ty, $rhs:ty) => {
+        #[allow(unused_lifetimes)]
+        impl<'a> PartialEq<$rhs> for $lhs {
+            #[inline]
+            fn eq(&self, other: &$rhs) -> bool {
+                let other: &[u8] = other.as_ref();
+                PartialEq::eq(self.as_bytes(), other)
+            }
+        }
+
+        #[allow(unused_lifetimes)]
+        impl<'a> PartialEq<$lhs> for $rhs {
+            #[inline]
+            fn eq(&self, other: &$lhs) -> bool {
+                let this: &[u8] = self.as_ref();
+                PartialEq::eq(this, other.as_bytes())
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+#[unstable(feature = "bstr_internals", issue = "none")]
+pub use impl_partial_eq;
+
+#[doc(hidden)]
+#[macro_export]
+#[unstable(feature = "bstr_internals", issue = "none")]
+macro_rules! impl_partial_eq_ord {
+    ($lhs:ty, $rhs:ty) => {
+        $crate::bstr::impl_partial_eq!($lhs, $rhs);
+
+        #[allow(unused_lifetimes)]
+        #[unstable(feature = "bstr", issue = "134915")]
+        impl<'a> PartialOrd<$rhs> for $lhs {
+            #[inline]
+            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
+                let other: &[u8] = other.as_ref();
+                PartialOrd::partial_cmp(self.as_bytes(), other)
+            }
+        }
+
+        #[allow(unused_lifetimes)]
+        #[unstable(feature = "bstr", issue = "134915")]
+        impl<'a> PartialOrd<$lhs> for $rhs {
+            #[inline]
+            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
+                let this: &[u8] = self.as_ref();
+                PartialOrd::partial_cmp(this, other.as_bytes())
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+#[unstable(feature = "bstr_internals", issue = "none")]
+pub use impl_partial_eq_ord;
+
+#[doc(hidden)]
+#[macro_export]
+#[unstable(feature = "bstr_internals", issue = "none")]
+macro_rules! impl_partial_eq_n {
+    ($lhs:ty, $rhs:ty) => {
+        #[allow(unused_lifetimes)]
+        #[unstable(feature = "bstr", issue = "134915")]
+        impl<const N: usize> PartialEq<$rhs> for $lhs {
+            #[inline]
+            fn eq(&self, other: &$rhs) -> bool {
+                let other: &[u8] = other.as_ref();
+                PartialEq::eq(self.as_bytes(), other)
+            }
+        }
+
+        #[allow(unused_lifetimes)]
+        #[unstable(feature = "bstr", issue = "134915")]
+        impl<const N: usize> PartialEq<$lhs> for $rhs {
+            #[inline]
+            fn eq(&self, other: &$lhs) -> bool {
+                let this: &[u8] = self.as_ref();
+                PartialEq::eq(this, other.as_bytes())
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+#[unstable(feature = "bstr_internals", issue = "none")]
+pub use impl_partial_eq_n;
+
+// PartialOrd with `[u8]` omitted to avoid inference failures
+impl_partial_eq!(ByteStr, [u8]);
+// PartialOrd with `&[u8]` omitted to avoid inference failures
+impl_partial_eq!(ByteStr, &[u8]);
+// PartialOrd with `str` omitted to avoid inference failures
+impl_partial_eq!(ByteStr, str);
+// PartialOrd with `&str` omitted to avoid inference failures
+impl_partial_eq!(ByteStr, &str);
+// PartialOrd with `[u8; N]` omitted to avoid inference failures
+impl_partial_eq_n!(ByteStr, [u8; N]);
+// PartialOrd with `[u8; N]` omitted to avoid inference failures
+impl_partial_eq_n!(ByteStr, &[u8; N]);
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Ord for ByteStr {
+    #[inline]
+    fn cmp(&self, other: &ByteStr) -> Ordering {
+        Ord::cmp(&self.0, &other.0)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl PartialOrd for ByteStr {
+    #[inline]
+    fn partial_cmp(&self, other: &ByteStr) -> Option<Ordering> {
+        PartialOrd::partial_cmp(&self.0, &other.0)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> TryFrom<&'a ByteStr> for &'a str {
+    type Error = crate::str::Utf8Error;
+
+    #[inline]
+    fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> {
+        crate::str::from_utf8(&s.0)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> TryFrom<&'a mut ByteStr> for &'a mut str {
+    type Error = crate::str::Utf8Error;
+
+    #[inline]
+    fn try_from(s: &'a mut ByteStr) -> Result<Self, Self::Error> {
+        crate::str::from_utf8_mut(&mut s.0)
+    }
+}
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index ec1aed53eaf..00300328b64 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -311,6 +311,16 @@ unsafe impl CloneToUninit for crate::ffi::CStr {
     }
 }
 
+#[unstable(feature = "bstr", issue = "134915")]
+unsafe impl CloneToUninit for crate::bstr::ByteStr {
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    unsafe fn clone_to_uninit(&self, dst: *mut u8) {
+        // SAFETY: ByteStr is a `#[repr(transparent)]` wrapper around `[u8]`
+        unsafe { self.as_bytes().clone_to_uninit(dst) }
+    }
+}
+
 /// Implementations of `Clone` for primitive types.
 ///
 /// Implementations that cannot be described in Rust
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index f58eab3b1b1..01ed3cc69a2 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -111,6 +111,8 @@
 #![feature(array_ptr_get)]
 #![feature(asm_experimental_arch)]
 #![feature(bigint_helper_methods)]
+#![feature(bstr)]
+#![feature(bstr_internals)]
 #![feature(const_carrying_mul_add)]
 #![feature(const_eval_select)]
 #![feature(core_intrinsics)]
@@ -336,6 +338,8 @@ pub mod ascii;
 pub mod asserting;
 #[unstable(feature = "async_iterator", issue = "79024")]
 pub mod async_iter;
+#[unstable(feature = "bstr", issue = "134915")]
+pub mod bstr;
 pub mod cell;
 pub mod char;
 pub mod ffi;
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index dbce64420ac..8089d616409 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -90,6 +90,26 @@ impl_zeroable_primitive!(
 ///
 /// assert_eq!(size_of::<Option<NonZero<u32>>>(), size_of::<u32>());
 /// ```
+///
+/// # Layout
+///
+/// `NonZero<T>` is guaranteed to have the same layout and bit validity as `T`
+/// with the exception that the all-zero bit pattern is invalid.
+/// `Option<NonZero<T>>` is guaranteed to be compatible with `T`, including in
+/// FFI.
+///
+/// Thanks to the [null pointer optimization], `NonZero<T>` and
+/// `Option<NonZero<T>>` are guaranteed to have the same size and alignment:
+///
+/// ```
+/// # use std::mem::{size_of, align_of};
+/// use std::num::NonZero;
+///
+/// assert_eq!(size_of::<NonZero<u32>>(), size_of::<Option<NonZero<u32>>>());
+/// assert_eq!(align_of::<NonZero<u32>>(), align_of::<Option<NonZero<u32>>>());
+/// ```
+///
+/// [null pointer optimization]: crate::option#representation
 #[stable(feature = "generic_nonzero", since = "1.79.0")]
 #[repr(transparent)]
 #[rustc_nonnull_optimization_guaranteed]
diff --git a/library/core/tests/bstr.rs b/library/core/tests/bstr.rs
new file mode 100644
index 00000000000..5fecd0a4084
--- /dev/null
+++ b/library/core/tests/bstr.rs
@@ -0,0 +1,54 @@
+#![feature(bstr)]
+
+use core::ByteStr;
+
+#[test]
+fn test_debug() {
+    assert_eq!(
+        r#""\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff""#,
+        format!("{:?}", ByteStr::new(b"\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff")),
+    );
+}
+
+#[test]
+fn test_display() {
+    let b1 = ByteStr::new("abc");
+    let b2 = ByteStr::new(b"\xf0\x28\x8c\xbc");
+
+    assert_eq!(&format!("{b1}"), "abc");
+    assert_eq!(&format!("{b2}"), "�(��");
+
+    assert_eq!(&format!("{b1:<7}!"), "abc    !");
+    assert_eq!(&format!("{b1:>7}!"), "    abc!");
+    assert_eq!(&format!("{b1:^7}!"), "  abc  !");
+    assert_eq!(&format!("{b1:^6}!"), " abc  !");
+    assert_eq!(&format!("{b1:-<7}!"), "abc----!");
+    assert_eq!(&format!("{b1:->7}!"), "----abc!");
+    assert_eq!(&format!("{b1:-^7}!"), "--abc--!");
+    assert_eq!(&format!("{b1:-^6}!"), "-abc--!");
+
+    assert_eq!(&format!("{b2:<7}!"), "�(��   !");
+    assert_eq!(&format!("{b2:>7}!"), "   �(��!");
+    assert_eq!(&format!("{b2:^7}!"), " �(��  !");
+    assert_eq!(&format!("{b2:^6}!"), " �(�� !");
+    assert_eq!(&format!("{b2:-<7}!"), "�(��---!");
+    assert_eq!(&format!("{b2:->7}!"), "---�(��!");
+    assert_eq!(&format!("{b2:-^7}!"), "-�(��--!");
+    assert_eq!(&format!("{b2:-^6}!"), "-�(��-!");
+
+    assert_eq!(&format!("{b1:<2}!"), "abc!");
+    assert_eq!(&format!("{b1:>2}!"), "abc!");
+    assert_eq!(&format!("{b1:^2}!"), "abc!");
+    assert_eq!(&format!("{b1:-<2}!"), "abc!");
+    assert_eq!(&format!("{b1:->2}!"), "abc!");
+    assert_eq!(&format!("{b1:-^2}!"), "abc!");
+
+    assert_eq!(&format!("{b2:<3}!"), "�(��!");
+    assert_eq!(&format!("{b2:>3}!"), "�(��!");
+    assert_eq!(&format!("{b2:^3}!"), "�(��!");
+    assert_eq!(&format!("{b2:^2}!"), "�(��!");
+    assert_eq!(&format!("{b2:-<3}!"), "�(��!");
+    assert_eq!(&format!("{b2:->3}!"), "�(��!");
+    assert_eq!(&format!("{b2:-^3}!"), "�(��!");
+    assert_eq!(&format!("{b2:-^2}!"), "�(��!");
+}
diff --git a/library/proc_macro/src/bridge/closure.rs b/library/proc_macro/src/bridge/closure.rs
index d371ae3cea0..524fdf53d6b 100644
--- a/library/proc_macro/src/bridge/closure.rs
+++ b/library/proc_macro/src/bridge/closure.rs
@@ -3,7 +3,7 @@
 use std::marker::PhantomData;
 
 #[repr(C)]
-pub struct Closure<'a, A, R> {
+pub(super) struct Closure<'a, A, R> {
     call: unsafe extern "C" fn(*mut Env, A) -> R,
     env: *mut Env,
     // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing
@@ -26,7 +26,7 @@ impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> {
 }
 
 impl<'a, A, R> Closure<'a, A, R> {
-    pub fn call(&mut self, arg: A) -> R {
+    pub(super) fn call(&mut self, arg: A) -> R {
         unsafe { (self.call)(self.env, arg) }
     }
 }
diff --git a/library/proc_macro/src/bridge/fxhash.rs b/library/proc_macro/src/bridge/fxhash.rs
index 3345e099a37..5f6b3d1b929 100644
--- a/library/proc_macro/src/bridge/fxhash.rs
+++ b/library/proc_macro/src/bridge/fxhash.rs
@@ -9,7 +9,7 @@ use std::hash::{BuildHasherDefault, Hasher};
 use std::ops::BitXor;
 
 /// Type alias for a hashmap using the `fx` hash algorithm.
-pub type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
+pub(super) type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
 
 /// A speedy hash algorithm for use within rustc. The hashmap in alloc by
 /// default uses SipHash which isn't quite as speedy as we want. In the compiler
@@ -23,7 +23,7 @@ pub type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
 /// similar or slightly worse than FNV, but the speed of the hash function
 /// itself is much higher because it works on up to 8 bytes at a time.
 #[derive(Default)]
-pub struct FxHasher {
+pub(super) struct FxHasher {
     hash: usize,
 }
 
diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs
index 202a8e04543..85fd7d13858 100644
--- a/library/proc_macro/src/bridge/rpc.rs
+++ b/library/proc_macro/src/bridge/rpc.rs
@@ -67,7 +67,7 @@ macro_rules! rpc_encode_decode {
                 mod tag {
                     #[repr(u8)] enum Tag { $($variant),* }
 
-                    $(pub const $variant: u8 = Tag::$variant as u8;)*
+                    $(pub(crate) const $variant: u8 = Tag::$variant as u8;)*
                 }
 
                 match self {
@@ -89,7 +89,7 @@ macro_rules! rpc_encode_decode {
                 mod tag {
                     #[repr(u8)] enum Tag { $($variant),* }
 
-                    $(pub const $variant: u8 = Tag::$variant as u8;)*
+                    $(pub(crate) const $variant: u8 = Tag::$variant as u8;)*
                 }
 
                 match u8::decode(r, s) {
diff --git a/library/proc_macro/src/bridge/selfless_reify.rs b/library/proc_macro/src/bridge/selfless_reify.rs
index 907ad256e4b..312a79152e2 100644
--- a/library/proc_macro/src/bridge/selfless_reify.rs
+++ b/library/proc_macro/src/bridge/selfless_reify.rs
@@ -44,7 +44,7 @@ macro_rules! define_reify_functions {
         fn $name:ident $(<$($param:ident),*>)?
             for $(extern $abi:tt)? fn($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty;
     )+) => {
-        $(pub const fn $name<
+        $(pub(super) const fn $name<
             $($($param,)*)?
             F: Fn($($arg_ty),*) -> $ret_ty + Copy
         >(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty {
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index b19c9cee75a..6611ce30a1b 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -32,6 +32,7 @@
 #![allow(internal_features)]
 #![deny(ffi_unwind_calls)]
 #![warn(rustdoc::unescaped_backticks)]
+#![warn(unreachable_pub)]
 
 #[unstable(feature = "proc_macro_internals", issue = "27812")]
 #[doc(hidden)]
diff --git a/library/std/src/bstr.rs b/library/std/src/bstr.rs
new file mode 100644
index 00000000000..dd491771628
--- /dev/null
+++ b/library/std/src/bstr.rs
@@ -0,0 +1,4 @@
+//! The `ByteStr` and `ByteString` types and trait implementations.
+
+#[unstable(feature = "bstr", issue = "134915")]
+pub use alloc::bstr::{ByteStr, ByteString};
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 9b752ed1443..1f8aac48a9a 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -2529,6 +2529,7 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
 /// limited to just these cases:
 ///
 /// * The `original` path is not a file or doesn't exist.
+/// * The 'link' path already exists.
 ///
 /// # Examples
 ///
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 39f234e4ba6..acb3a0578e5 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -320,6 +320,8 @@
 // Library features (core):
 // tidy-alphabetical-start
 #![feature(array_chunks)]
+#![feature(bstr)]
+#![feature(bstr_internals)]
 #![feature(c_str_module)]
 #![feature(char_internals)]
 #![feature(clone_to_uninit)]
@@ -581,6 +583,8 @@ pub mod f64;
 pub mod thread;
 pub mod ascii;
 pub mod backtrace;
+#[unstable(feature = "bstr", issue = "134915")]
+pub mod bstr;
 pub mod collections;
 pub mod env;
 pub mod error;
diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs
index 4ccd825bf8d..52c80917623 100644
--- a/library/test/src/cli.rs
+++ b/library/test/src/cli.rs
@@ -44,7 +44,7 @@ impl TestOpts {
 }
 
 /// Result of parsing the options.
-pub type OptRes = Result<TestOpts, String>;
+pub(crate) type OptRes = Result<TestOpts, String>;
 /// Result of parsing the option part.
 type OptPartRes<T> = Result<T, String>;
 
diff --git a/library/test/src/console.rs b/library/test/src/console.rs
index 4d4cdcf4d7b..024ef48fc51 100644
--- a/library/test/src/console.rs
+++ b/library/test/src/console.rs
@@ -20,7 +20,7 @@ use super::types::{NamePadding, TestDesc, TestDescAndFn};
 use super::{filter_tests, run_tests, term};
 
 /// Generic wrapper over stdout.
-pub enum OutputLocation<T> {
+pub(crate) enum OutputLocation<T> {
     Pretty(Box<term::StdoutTerminal>),
     Raw(T),
 }
@@ -41,7 +41,7 @@ impl<T: Write> Write for OutputLocation<T> {
     }
 }
 
-pub struct ConsoleTestDiscoveryState {
+pub(crate) struct ConsoleTestDiscoveryState {
     pub log_out: Option<File>,
     pub tests: usize,
     pub benchmarks: usize,
@@ -49,7 +49,7 @@ pub struct ConsoleTestDiscoveryState {
 }
 
 impl ConsoleTestDiscoveryState {
-    pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestDiscoveryState> {
+    pub(crate) fn new(opts: &TestOpts) -> io::Result<ConsoleTestDiscoveryState> {
         let log_out = match opts.logfile {
             Some(ref path) => Some(File::create(path)?),
             None => None,
@@ -58,7 +58,7 @@ impl ConsoleTestDiscoveryState {
         Ok(ConsoleTestDiscoveryState { log_out, tests: 0, benchmarks: 0, ignored: 0 })
     }
 
-    pub fn write_log<F, S>(&mut self, msg: F) -> io::Result<()>
+    pub(crate) fn write_log<F, S>(&mut self, msg: F) -> io::Result<()>
     where
         S: AsRef<str>,
         F: FnOnce() -> S,
@@ -74,7 +74,7 @@ impl ConsoleTestDiscoveryState {
     }
 }
 
-pub struct ConsoleTestState {
+pub(crate) struct ConsoleTestState {
     pub log_out: Option<File>,
     pub total: usize,
     pub passed: usize,
@@ -92,7 +92,7 @@ pub struct ConsoleTestState {
 }
 
 impl ConsoleTestState {
-    pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> {
+    pub(crate) fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> {
         let log_out = match opts.logfile {
             Some(ref path) => Some(File::create(path)?),
             None => None,
@@ -116,7 +116,7 @@ impl ConsoleTestState {
         })
     }
 
-    pub fn write_log<F, S>(&mut self, msg: F) -> io::Result<()>
+    pub(crate) fn write_log<F, S>(&mut self, msg: F) -> io::Result<()>
     where
         S: AsRef<str>,
         F: FnOnce() -> S,
@@ -131,7 +131,7 @@ impl ConsoleTestState {
         }
     }
 
-    pub fn write_log_result(
+    pub(crate) fn write_log_result(
         &mut self,
         test: &TestDesc,
         result: &TestResult,
@@ -170,7 +170,7 @@ impl ConsoleTestState {
 }
 
 // List the tests to console, and optionally to logfile. Filters are honored.
-pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
+pub(crate) fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
     let output = match term::stdout() {
         None => OutputLocation::Raw(io::stdout().lock()),
         Some(t) => OutputLocation::Pretty(t),
diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs
index aa1c50641cb..92c1c0716f1 100644
--- a/library/test/src/formatters/json.rs
+++ b/library/test/src/formatters/json.rs
@@ -13,7 +13,7 @@ pub(crate) struct JsonFormatter<T> {
 }
 
 impl<T: Write> JsonFormatter<T> {
-    pub fn new(out: OutputLocation<T>) -> Self {
+    pub(crate) fn new(out: OutputLocation<T>) -> Self {
         Self { out }
     }
 
diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs
index 96b43200840..57b1b0fecee 100644
--- a/library/test/src/formatters/junit.rs
+++ b/library/test/src/formatters/junit.rs
@@ -8,13 +8,13 @@ use crate::test_result::TestResult;
 use crate::time;
 use crate::types::{TestDesc, TestType};
 
-pub struct JunitFormatter<T> {
+pub(crate) struct JunitFormatter<T> {
     out: OutputLocation<T>,
     results: Vec<(TestDesc, TestResult, Duration, Vec<u8>)>,
 }
 
 impl<T: Write> JunitFormatter<T> {
-    pub fn new(out: OutputLocation<T>) -> Self {
+    pub(crate) fn new(out: OutputLocation<T>) -> Self {
         Self { out, results: Vec::new() }
     }
 
diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs
index 7089eae4330..bf3fc40db41 100644
--- a/library/test/src/formatters/pretty.rs
+++ b/library/test/src/formatters/pretty.rs
@@ -20,7 +20,7 @@ pub(crate) struct PrettyFormatter<T> {
 }
 
 impl<T: Write> PrettyFormatter<T> {
-    pub fn new(
+    pub(crate) fn new(
         out: OutputLocation<T>,
         use_color: bool,
         max_name_len: usize,
@@ -31,19 +31,19 @@ impl<T: Write> PrettyFormatter<T> {
     }
 
     #[cfg(test)]
-    pub fn output_location(&self) -> &OutputLocation<T> {
+    pub(crate) fn output_location(&self) -> &OutputLocation<T> {
         &self.out
     }
 
-    pub fn write_ok(&mut self) -> io::Result<()> {
+    pub(crate) fn write_ok(&mut self) -> io::Result<()> {
         self.write_short_result("ok", term::color::GREEN)
     }
 
-    pub fn write_failed(&mut self) -> io::Result<()> {
+    pub(crate) fn write_failed(&mut self) -> io::Result<()> {
         self.write_short_result("FAILED", term::color::RED)
     }
 
-    pub fn write_ignored(&mut self, message: Option<&'static str>) -> io::Result<()> {
+    pub(crate) fn write_ignored(&mut self, message: Option<&'static str>) -> io::Result<()> {
         if let Some(message) = message {
             self.write_short_result(&format!("ignored, {message}"), term::color::YELLOW)
         } else {
@@ -51,15 +51,15 @@ impl<T: Write> PrettyFormatter<T> {
         }
     }
 
-    pub fn write_time_failed(&mut self) -> io::Result<()> {
+    pub(crate) fn write_time_failed(&mut self) -> io::Result<()> {
         self.write_short_result("FAILED (time limit exceeded)", term::color::RED)
     }
 
-    pub fn write_bench(&mut self) -> io::Result<()> {
+    pub(crate) fn write_bench(&mut self) -> io::Result<()> {
         self.write_pretty("bench", term::color::CYAN)
     }
 
-    pub fn write_short_result(
+    pub(crate) fn write_short_result(
         &mut self,
         result: &str,
         color: term::color::Color,
@@ -67,7 +67,7 @@ impl<T: Write> PrettyFormatter<T> {
         self.write_pretty(result, color)
     }
 
-    pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
+    pub(crate) fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
         match self.out {
             OutputLocation::Pretty(ref mut term) => {
                 if self.use_color {
@@ -86,7 +86,7 @@ impl<T: Write> PrettyFormatter<T> {
         }
     }
 
-    pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
+    pub(crate) fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
         let s = s.as_ref();
         self.out.write_all(s.as_bytes())?;
         self.out.flush()
@@ -154,15 +154,15 @@ impl<T: Write> PrettyFormatter<T> {
         Ok(())
     }
 
-    pub fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> {
+    pub(crate) fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> {
         self.write_results(&state.not_failures, "successes")
     }
 
-    pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
+    pub(crate) fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
         self.write_results(&state.failures, "failures")
     }
 
-    pub fn write_time_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
+    pub(crate) fn write_time_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
         self.write_results(&state.time_failures, "failures (time limit exceeded)")
     }
 
diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs
index 534aa2f3311..b28120ab56e 100644
--- a/library/test/src/formatters/terse.rs
+++ b/library/test/src/formatters/terse.rs
@@ -25,7 +25,7 @@ pub(crate) struct TerseFormatter<T> {
 }
 
 impl<T: Write> TerseFormatter<T> {
-    pub fn new(
+    pub(crate) fn new(
         out: OutputLocation<T>,
         use_color: bool,
         max_name_len: usize,
@@ -42,11 +42,11 @@ impl<T: Write> TerseFormatter<T> {
         }
     }
 
-    pub fn write_ok(&mut self) -> io::Result<()> {
+    pub(crate) fn write_ok(&mut self) -> io::Result<()> {
         self.write_short_result(".", term::color::GREEN)
     }
 
-    pub fn write_failed(&mut self, name: &str) -> io::Result<()> {
+    pub(crate) fn write_failed(&mut self, name: &str) -> io::Result<()> {
         // Put failed tests on their own line and include the test name, so that it's faster
         // to see which test failed without having to wait for them all to run.
 
@@ -62,15 +62,15 @@ impl<T: Write> TerseFormatter<T> {
         self.write_plain("\n")
     }
 
-    pub fn write_ignored(&mut self) -> io::Result<()> {
+    pub(crate) fn write_ignored(&mut self) -> io::Result<()> {
         self.write_short_result("i", term::color::YELLOW)
     }
 
-    pub fn write_bench(&mut self) -> io::Result<()> {
+    pub(crate) fn write_bench(&mut self) -> io::Result<()> {
         self.write_pretty("bench", term::color::CYAN)
     }
 
-    pub fn write_short_result(
+    pub(crate) fn write_short_result(
         &mut self,
         result: &str,
         color: term::color::Color,
@@ -95,7 +95,7 @@ impl<T: Write> TerseFormatter<T> {
         Ok(())
     }
 
-    pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
+    pub(crate) fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
         match self.out {
             OutputLocation::Pretty(ref mut term) => {
                 if self.use_color {
@@ -114,13 +114,13 @@ impl<T: Write> TerseFormatter<T> {
         }
     }
 
-    pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
+    pub(crate) fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
         let s = s.as_ref();
         self.out.write_all(s.as_bytes())?;
         self.out.flush()
     }
 
-    pub fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> {
+    pub(crate) fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> {
         self.write_plain("\nsuccesses:\n")?;
         let mut successes = Vec::new();
         let mut stdouts = String::new();
@@ -146,7 +146,7 @@ impl<T: Write> TerseFormatter<T> {
         Ok(())
     }
 
-    pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
+    pub(crate) fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
         self.write_plain("\nfailures:\n")?;
         let mut failures = Vec::new();
         let mut fail_out = String::new();
diff --git a/library/test/src/helpers/concurrency.rs b/library/test/src/helpers/concurrency.rs
index b1545cbec43..6648b669125 100644
--- a/library/test/src/helpers/concurrency.rs
+++ b/library/test/src/helpers/concurrency.rs
@@ -4,7 +4,7 @@
 use std::num::NonZero;
 use std::{env, thread};
 
-pub fn get_concurrency() -> usize {
+pub(crate) fn get_concurrency() -> usize {
     if let Ok(value) = env::var("RUST_TEST_THREADS") {
         match value.parse::<NonZero<usize>>().ok() {
             Some(n) => n.get(),
diff --git a/library/test/src/helpers/mod.rs b/library/test/src/helpers/mod.rs
index 3c79b90b167..2fb29b4c7be 100644
--- a/library/test/src/helpers/mod.rs
+++ b/library/test/src/helpers/mod.rs
@@ -1,6 +1,6 @@
 //! Module with common helpers not directly related to tests
 //! but used in `libtest`.
 
-pub mod concurrency;
-pub mod metrics;
-pub mod shuffle;
+pub(crate) mod concurrency;
+pub(crate) mod metrics;
+pub(crate) mod shuffle;
diff --git a/library/test/src/helpers/shuffle.rs b/library/test/src/helpers/shuffle.rs
index 14389eb0e37..53d1d0e42d4 100644
--- a/library/test/src/helpers/shuffle.rs
+++ b/library/test/src/helpers/shuffle.rs
@@ -4,7 +4,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
 use crate::cli::TestOpts;
 use crate::types::{TestDescAndFn, TestId, TestName};
 
-pub fn get_shuffle_seed(opts: &TestOpts) -> Option<u64> {
+pub(crate) fn get_shuffle_seed(opts: &TestOpts) -> Option<u64> {
     opts.shuffle_seed.or_else(|| {
         if opts.shuffle {
             Some(
@@ -19,7 +19,7 @@ pub fn get_shuffle_seed(opts: &TestOpts) -> Option<u64> {
     })
 }
 
-pub fn shuffle_tests(shuffle_seed: u64, tests: &mut [(TestId, TestDescAndFn)]) {
+pub(crate) fn shuffle_tests(shuffle_seed: u64, tests: &mut [(TestId, TestDescAndFn)]) {
     let test_names: Vec<&TestName> = tests.iter().map(|test| &test.1.desc.name).collect();
     let test_names_hash = calculate_hash(&test_names);
     let mut rng = Rng::new(shuffle_seed, test_names_hash);
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 47407df909b..54f7e4ae79f 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -27,6 +27,7 @@
 #![feature(thread_spawn_hook)]
 #![allow(internal_features)]
 #![warn(rustdoc::unescaped_backticks)]
+#![warn(unreachable_pub)]
 
 pub use cli::TestOpts;
 
diff --git a/library/test/src/options.rs b/library/test/src/options.rs
index 3eaad59474a..7a5c55f4e24 100644
--- a/library/test/src/options.rs
+++ b/library/test/src/options.rs
@@ -2,7 +2,7 @@
 
 /// Number of times to run a benchmarked function
 #[derive(Clone, PartialEq, Eq)]
-pub enum BenchMode {
+pub(crate) enum BenchMode {
     Auto,
     Single,
 }
diff --git a/library/test/src/stats/tests.rs b/library/test/src/stats/tests.rs
index 4b209dcf214..7804ddc9291 100644
--- a/library/test/src/stats/tests.rs
+++ b/library/test/src/stats/tests.rs
@@ -573,13 +573,13 @@ fn test_sum_f64_between_ints_that_sum_to_0() {
 }
 
 #[bench]
-pub fn sum_three_items(b: &mut Bencher) {
+fn sum_three_items(b: &mut Bencher) {
     b.iter(|| {
         [1e20f64, 1.5f64, -1e20f64].sum();
     })
 }
 #[bench]
-pub fn sum_many_f64(b: &mut Bencher) {
+fn sum_many_f64(b: &mut Bencher) {
     let nums = [-1e30f64, 1e60, 1e30, 1.0, -1e60];
     let v = (0..500).map(|i| nums[i % 5]).collect::<Vec<_>>();
 
@@ -589,4 +589,4 @@ pub fn sum_many_f64(b: &mut Bencher) {
 }
 
 #[bench]
-pub fn no_iter(_: &mut Bencher) {}
+fn no_iter(_: &mut Bencher) {}
diff --git a/library/test/src/term.rs b/library/test/src/term.rs
index e736e85d469..d9880a77640 100644
--- a/library/test/src/term.rs
+++ b/library/test/src/term.rs
@@ -62,7 +62,7 @@ pub(crate) mod color {
 
 /// A terminal with similar capabilities to an ANSI Terminal
 /// (foreground/background colors etc).
-pub trait Terminal: Write {
+pub(crate) trait Terminal: Write {
     /// Sets the foreground color to the given color.
     ///
     /// If the color is a bright color, but the terminal only supports 8 colors,
diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs
index 79fe07bc1ac..73dcc2e2a0c 100644
--- a/library/test/src/test_result.rs
+++ b/library/test/src/test_result.rs
@@ -12,7 +12,7 @@ use super::types::TestDesc;
 // Return code for secondary process.
 // Start somewhere other than 0 so we know the return code means what we think
 // it means.
-pub const TR_OK: i32 = 50;
+pub(crate) const TR_OK: i32 = 50;
 
 // On Windows we use __fastfail to abort, which is documented to use this
 // exception code.
@@ -39,7 +39,7 @@ pub enum TestResult {
 
 /// Creates a `TestResult` depending on the raw result of test execution
 /// and associated data.
-pub fn calc_result<'a>(
+pub(crate) fn calc_result<'a>(
     desc: &TestDesc,
     task_result: Result<(), &'a (dyn Any + 'static + Send)>,
     time_opts: Option<&time::TestTimeOptions>,
@@ -93,7 +93,7 @@ pub fn calc_result<'a>(
 }
 
 /// Creates a `TestResult` depending on the exit code of test subprocess.
-pub fn get_result_from_exit_code(
+pub(crate) fn get_result_from_exit_code(
     desc: &TestDesc,
     status: ExitStatus,
     time_opts: Option<&time::TestTimeOptions>,
diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs
index e85e61090a9..abeb3642169 100644
--- a/library/test/src/tests.rs
+++ b/library/test/src/tests.rs
@@ -78,7 +78,7 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
 }
 
 #[test]
-pub fn do_not_run_ignored_tests() {
+fn do_not_run_ignored_tests() {
     fn f() -> Result<(), String> {
         panic!();
     }
@@ -106,7 +106,7 @@ pub fn do_not_run_ignored_tests() {
 }
 
 #[test]
-pub fn ignored_tests_result_in_ignored() {
+fn ignored_tests_result_in_ignored() {
     fn f() -> Result<(), String> {
         Ok(())
     }
@@ -479,7 +479,7 @@ fn parse_include_ignored_flag() {
 }
 
 #[test]
-pub fn filter_for_ignored_option() {
+fn filter_for_ignored_option() {
     // When we run ignored tests the test filter should filter out all the
     // unignored tests and flip the ignore flag on the rest to false
 
@@ -496,7 +496,7 @@ pub fn filter_for_ignored_option() {
 }
 
 #[test]
-pub fn run_include_ignored_option() {
+fn run_include_ignored_option() {
     // When we "--include-ignored" tests, the ignore flag should be set to false on
     // all tests and no test filtered out
 
@@ -513,7 +513,7 @@ pub fn run_include_ignored_option() {
 }
 
 #[test]
-pub fn exclude_should_panic_option() {
+fn exclude_should_panic_option() {
     let mut opts = TestOpts::new();
     opts.run_tests = true;
     opts.exclude_should_panic = true;
@@ -544,7 +544,7 @@ pub fn exclude_should_panic_option() {
 }
 
 #[test]
-pub fn exact_filter_match() {
+fn exact_filter_match() {
     fn tests() -> Vec<TestDescAndFn> {
         ["base", "base::test", "base::test1", "base::test2"]
             .into_iter()
@@ -667,7 +667,7 @@ fn sample_tests() -> Vec<TestDescAndFn> {
 }
 
 #[test]
-pub fn shuffle_tests() {
+fn shuffle_tests() {
     let mut opts = TestOpts::new();
     opts.shuffle = true;
 
@@ -686,7 +686,7 @@ pub fn shuffle_tests() {
 }
 
 #[test]
-pub fn shuffle_tests_with_seed() {
+fn shuffle_tests_with_seed() {
     let mut opts = TestOpts::new();
     opts.shuffle = true;
 
@@ -704,7 +704,7 @@ pub fn shuffle_tests_with_seed() {
 }
 
 #[test]
-pub fn order_depends_on_more_than_seed() {
+fn order_depends_on_more_than_seed() {
     let mut opts = TestOpts::new();
     opts.shuffle = true;
 
@@ -732,7 +732,7 @@ pub fn order_depends_on_more_than_seed() {
 }
 
 #[test]
-pub fn test_metricmap_compare() {
+fn test_metricmap_compare() {
     let mut m1 = MetricMap::new();
     let mut m2 = MetricMap::new();
     m1.insert_metric("in-both-noise", 1000.0, 200.0);
@@ -755,7 +755,7 @@ pub fn test_metricmap_compare() {
 }
 
 #[test]
-pub fn test_bench_once_no_iter() {
+fn test_bench_once_no_iter() {
     fn f(_: &mut Bencher) -> Result<(), String> {
         Ok(())
     }
@@ -763,7 +763,7 @@ pub fn test_bench_once_no_iter() {
 }
 
 #[test]
-pub fn test_bench_once_iter() {
+fn test_bench_once_iter() {
     fn f(b: &mut Bencher) -> Result<(), String> {
         b.iter(|| {});
         Ok(())
@@ -772,7 +772,7 @@ pub fn test_bench_once_iter() {
 }
 
 #[test]
-pub fn test_bench_no_iter() {
+fn test_bench_no_iter() {
     fn f(_: &mut Bencher) -> Result<(), String> {
         Ok(())
     }
@@ -799,7 +799,7 @@ pub fn test_bench_no_iter() {
 }
 
 #[test]
-pub fn test_bench_iter() {
+fn test_bench_iter() {
     fn f(b: &mut Bencher) -> Result<(), String> {
         b.iter(|| {});
         Ok(())
diff --git a/library/test/src/time.rs b/library/test/src/time.rs
index 02ae050db55..f63b156b3dc 100644
--- a/library/test/src/time.rs
+++ b/library/test/src/time.rs
@@ -11,7 +11,7 @@ use std::{env, fmt};
 
 use super::types::{TestDesc, TestType};
 
-pub const TEST_WARN_TIMEOUT_S: u64 = 60;
+pub(crate) const TEST_WARN_TIMEOUT_S: u64 = 60;
 
 /// This small module contains constants used by `report-time` option.
 /// Those constants values will be used if corresponding environment variables are not set.
@@ -22,42 +22,42 @@ pub const TEST_WARN_TIMEOUT_S: u64 = 60;
 ///
 /// Example of the expected format is `RUST_TEST_TIME_xxx=100,200`, where 100 means
 /// warn time, and 200 means critical time.
-pub mod time_constants {
+pub(crate) mod time_constants {
     use std::time::Duration;
 
     use super::TEST_WARN_TIMEOUT_S;
 
     /// Environment variable for overriding default threshold for unit-tests.
-    pub const UNIT_ENV_NAME: &str = "RUST_TEST_TIME_UNIT";
+    pub(crate) const UNIT_ENV_NAME: &str = "RUST_TEST_TIME_UNIT";
 
     // Unit tests are supposed to be really quick.
-    pub const UNIT_WARN: Duration = Duration::from_millis(50);
-    pub const UNIT_CRITICAL: Duration = Duration::from_millis(100);
+    pub(crate) const UNIT_WARN: Duration = Duration::from_millis(50);
+    pub(crate) const UNIT_CRITICAL: Duration = Duration::from_millis(100);
 
     /// Environment variable for overriding default threshold for unit-tests.
-    pub const INTEGRATION_ENV_NAME: &str = "RUST_TEST_TIME_INTEGRATION";
+    pub(crate) const INTEGRATION_ENV_NAME: &str = "RUST_TEST_TIME_INTEGRATION";
 
     // Integration tests may have a lot of work, so they can take longer to execute.
-    pub const INTEGRATION_WARN: Duration = Duration::from_millis(500);
-    pub const INTEGRATION_CRITICAL: Duration = Duration::from_millis(1000);
+    pub(crate) const INTEGRATION_WARN: Duration = Duration::from_millis(500);
+    pub(crate) const INTEGRATION_CRITICAL: Duration = Duration::from_millis(1000);
 
     /// Environment variable for overriding default threshold for unit-tests.
-    pub const DOCTEST_ENV_NAME: &str = "RUST_TEST_TIME_DOCTEST";
+    pub(crate) const DOCTEST_ENV_NAME: &str = "RUST_TEST_TIME_DOCTEST";
 
     // Doctests are similar to integration tests, because they can include a lot of
     // initialization code.
-    pub const DOCTEST_WARN: Duration = INTEGRATION_WARN;
-    pub const DOCTEST_CRITICAL: Duration = INTEGRATION_CRITICAL;
+    pub(crate) const DOCTEST_WARN: Duration = INTEGRATION_WARN;
+    pub(crate) const DOCTEST_CRITICAL: Duration = INTEGRATION_CRITICAL;
 
     // Do not suppose anything about unknown tests, base limits on the
     // `TEST_WARN_TIMEOUT_S` constant.
-    pub const UNKNOWN_WARN: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S);
-    pub const UNKNOWN_CRITICAL: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S * 2);
+    pub(crate) const UNKNOWN_WARN: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S);
+    pub(crate) const UNKNOWN_CRITICAL: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S * 2);
 }
 
 /// Returns an `Instance` object denoting when the test should be considered
 /// timed out.
-pub fn get_default_test_timeout() -> Instant {
+pub(crate) fn get_default_test_timeout() -> Instant {
     Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S)
 }
 
@@ -73,7 +73,7 @@ impl fmt::Display for TestExecTime {
 
 /// The measured execution time of the whole test suite.
 #[derive(Debug, Clone, Default, PartialEq)]
-pub struct TestSuiteExecTime(pub Duration);
+pub(crate) struct TestSuiteExecTime(pub Duration);
 
 impl fmt::Display for TestSuiteExecTime {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs
index 563b715fa64..98b8635132b 100644
--- a/src/bootstrap/src/core/build_steps/gcc.rs
+++ b/src/bootstrap/src/core/build_steps/gcc.rs
@@ -12,6 +12,8 @@ use std::fs;
 use std::path::PathBuf;
 use std::sync::OnceLock;
 
+use build_helper::ci::CiEnv;
+
 use crate::Kind;
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
@@ -112,16 +114,60 @@ impl Step for Gcc {
             return true;
         }
 
-        command(root.join("contrib/download_prerequisites")).current_dir(&root).run(builder);
-        command(root.join("configure"))
+        // GCC creates files (e.g. symlinks to the downloaded dependencies)
+        // in the source directory, which does not work with our CI setup, where we mount
+        // source directories as read-only on Linux.
+        // Therefore, as a part of the build in CI, we first copy the whole source directory
+        // to the build directory, and perform the build from there.
+        let src_dir = if CiEnv::is_ci() {
+            let src_dir = builder.gcc_out(target).join("src");
+            if src_dir.exists() {
+                builder.remove_dir(&src_dir);
+            }
+            builder.create_dir(&src_dir);
+            builder.cp_link_r(&root, &src_dir);
+            src_dir
+        } else {
+            root
+        };
+
+        command(src_dir.join("contrib/download_prerequisites")).current_dir(&src_dir).run(builder);
+        let mut configure_cmd = command(src_dir.join("configure"));
+        configure_cmd
             .current_dir(&out_dir)
+            // On CI, we compile GCC with Clang.
+            // The -Wno-everything flag is needed to make GCC compile with Clang 19.
+            // `-g -O2` are the default flags that are otherwise used by Make.
+            // FIXME(kobzol): change the flags once we have [gcc] configuration in config.toml.
+            .env("CXXFLAGS", "-Wno-everything -g -O2")
+            .env("CFLAGS", "-Wno-everything -g -O2")
             .arg("--enable-host-shared")
             .arg("--enable-languages=jit")
             .arg("--enable-checking=release")
             .arg("--disable-bootstrap")
             .arg("--disable-multilib")
-            .arg(format!("--prefix={}", install_dir.display()))
-            .run(builder);
+            .arg(format!("--prefix={}", install_dir.display()));
+        let cc = builder.build.cc(target).display().to_string();
+        let cc = builder
+            .build
+            .config
+            .ccache
+            .as_ref()
+            .map_or_else(|| cc.clone(), |ccache| format!("{ccache} {cc}"));
+        configure_cmd.env("CC", cc);
+
+        if let Ok(ref cxx) = builder.build.cxx(target) {
+            let cxx = cxx.display().to_string();
+            let cxx = builder
+                .build
+                .config
+                .ccache
+                .as_ref()
+                .map_or_else(|| cxx.clone(), |ccache| format!("{ccache} {cxx}"));
+            configure_cmd.env("CXX", cxx);
+        }
+        configure_cmd.run(builder);
+
         command("make").current_dir(&out_dir).arg(format!("-j{}", builder.jobs())).run(builder);
         command("make").current_dir(&out_dir).arg("install").run(builder);
 
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index dde6fe7f6d0..3a396230582 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -34,6 +34,7 @@ RUN yum upgrade -y && \
       python3 \
       unzip \
       wget \
+      flex \
       xz \
       zlib-devel.i686 \
       zlib-devel.x86_64 \
diff --git a/src/ci/docker/scripts/build-zstd.sh b/src/ci/docker/scripts/build-zstd.sh
index a3d37ccc311..cffa7151e38 100755
--- a/src/ci/docker/scripts/build-zstd.sh
+++ b/src/ci/docker/scripts/build-zstd.sh
@@ -25,5 +25,11 @@ cd zstd-$ZSTD
 CFLAGS=-fPIC hide_output make -j$(nproc) VERBOSE=1
 hide_output make install
 
+# It doesn't seem to be possible to move destination directory
+# of the `make install` above. We thus copy the built artifacts
+# manually to our custom rustroot, so that it can be found through
+# LD_LIBRARY_PATH.
+cp /usr/local/lib/libzstd* /rustroot/lib64
+
 cd ..
 rm -rf zstd-$ZSTD
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 5e95e3721df..7730d29d28f 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -52,6 +52,8 @@ runners:
     free_disk: true
     os: ubuntu-22.04-arm
 
+  - &job-aarch64-linux-8c
+    os: ubuntu-22.04-arm64-8core-32gb
 envs:
   env-x86_64-apple-tests: &env-x86_64-apple-tests
     SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
@@ -144,7 +146,7 @@ auto:
   - name: dist-aarch64-linux
     env:
       CODEGEN_BACKENDS: llvm,cranelift
-    <<: *job-aarch64-linux
+    <<: *job-aarch64-linux-8c
 
   - name: dist-android
     <<: *job-linux-4c
diff --git a/src/ci/scripts/free-disk-space.sh b/src/ci/scripts/free-disk-space.sh
new file mode 100755
index 00000000000..4a7dad0090b
--- /dev/null
+++ b/src/ci/scripts/free-disk-space.sh
@@ -0,0 +1,142 @@
+#!/bin/bash
+
+# Free disk space on Linux GitHub action runners
+# Script inspired by https://github.com/jlumbroso/free-disk-space
+
+# print a line of the specified character
+printSeparationLine() {
+    for ((i = 0; i < 80; i++)); do
+        printf "%s" "$1"
+    done
+    printf "\n"
+}
+
+# compute available space
+# REF: https://unix.stackexchange.com/a/42049/60849
+# REF: https://stackoverflow.com/a/450821/408734
+getAvailableSpace() { echo $(df -a | awk 'NR > 1 {avail+=$4} END {print avail}'); }
+
+# make Kb human readable (assume the input is Kb)
+# REF: https://unix.stackexchange.com/a/44087/60849
+formatByteCount() { echo $(numfmt --to=iec-i --suffix=B --padding=7 $1'000'); }
+
+# macro to output saved space
+printSavedSpace() {
+    # Disk space before the operation
+    local before=${1}
+    local title=${2:-}
+
+    local after
+    after=$(getAvailableSpace)
+    local saved=$((after - before))
+
+    echo ""
+    printSeparationLine "*"
+    if [ -n "${title}" ]; then
+        echo "=> ${title}: Saved $(formatByteCount "$saved")"
+    else
+        echo "=> Saved $(formatByteCount "$saved")"
+    fi
+    printSeparationLine "*"
+    echo ""
+}
+
+# macro to print output of df with caption
+printDF() {
+    local caption=${1}
+
+    printSeparationLine "="
+    echo "${caption}"
+    echo ""
+    echo "$ df -h"
+    echo ""
+    df -h
+    printSeparationLine "="
+}
+
+removeDir() {
+    dir=${1}
+
+    local before
+    before=$(getAvailableSpace)
+
+    sudo rm -rf "$dir" || true
+
+    printSavedSpace "$before" "$dir"
+}
+
+execAndMeasureSpaceChange() {
+    local operation=${1} # Function to execute
+    local title=${2}
+
+    local before
+    before=$(getAvailableSpace)
+    $operation
+
+    printSavedSpace "$before" "$title"
+}
+
+# Remove large packages
+# REF: https://github.com/apache/flink/blob/master/tools/azure-pipelines/free_disk_space.sh
+cleanPackages() {
+    sudo apt-get -qq remove -y --fix-missing \
+        '^aspnetcore-.*'       \
+        '^dotnet-.*'           \
+        '^llvm-.*'             \
+        'php.*'                \
+        '^mongodb-.*'          \
+        '^mysql-.*'            \
+        'azure-cli'            \
+        'google-chrome-stable' \
+        'firefox'              \
+        'powershell'           \
+        'mono-devel'           \
+        'libgl1-mesa-dri'      \
+        'google-cloud-sdk'     \
+        'google-cloud-cli'
+
+    sudo apt-get autoremove -y || echo "::warning::The command [sudo apt-get autoremove -y] failed"
+    sudo apt-get clean || echo "::warning::The command [sudo apt-get clean] failed failed"
+}
+
+# Remove Docker images
+cleanDocker() {
+    echo "Removing the following docker images:"
+    sudo docker image ls
+    echo "Removing docker images..."
+    sudo docker image prune --all --force || true
+}
+
+# Remove Swap storage
+cleanSwap() {
+    sudo swapoff -a || true
+    sudo rm -rf /mnt/swapfile || true
+    free -h
+}
+
+# Display initial disk space stats
+
+AVAILABLE_INITIAL=$(getAvailableSpace)
+
+printDF "BEFORE CLEAN-UP:"
+echo ""
+
+removeDir /usr/local/lib/android
+removeDir /usr/share/dotnet
+
+# Haskell runtime
+removeDir /opt/ghc
+removeDir /usr/local/.ghcup
+
+execAndMeasureSpaceChange cleanPackages "Large misc. packages"
+execAndMeasureSpaceChange cleanDocker "Docker images"
+execAndMeasureSpaceChange cleanSwap "Swap storage"
+
+# Output saved space statistic
+echo ""
+printDF "AFTER CLEAN-UP:"
+
+echo ""
+echo ""
+
+printSavedSpace "$AVAILABLE_INITIAL" "Total saved"
diff --git a/src/doc/rustc-dev-guide/.github/workflows/ci.yml b/src/doc/rustc-dev-guide/.github/workflows/ci.yml
index 07c20d8d88b..006bcce44b3 100644
--- a/src/doc/rustc-dev-guide/.github/workflows/ci.yml
+++ b/src/doc/rustc-dev-guide/.github/workflows/ci.yml
@@ -35,12 +35,13 @@ jobs:
             ~/.cargo/bin
           key: ${{ runner.os }}-${{ env.MDBOOK_VERSION }}--${{ env.MDBOOK_LINKCHECK2_VERSION }}--${{ env.MDBOOK_TOC_VERSION }}--${{ env.MDBOOK_MERMAID_VERSION }}
 
-      - name: Cache linkcheck
-        uses: actions/cache@v4
+      - name: Restore cached Linkcheck
+        if: github.event_name == 'schedule'
+        id: cache-linkcheck-restore
+        uses: actions/cache/restore@v4
         with:
-          path: |
-            ~/book/linkcheck
-          key: ${{ runner.os }}-${{ hashFiles('./book/linkcheck') }}
+          path: book/linkcheck/cache.json
+          key: linkcheck--${{ env.MDBOOK_LINKCHECK2_VERSION }}
 
       - name: Install latest nightly Rust toolchain
         if: steps.mdbook-cache.outputs.cache-hit != 'true'
@@ -59,6 +60,14 @@ jobs:
       - name: Check build
         run: ENABLE_LINKCHECK=1 mdbook build
 
+      - name: Save cached Linkcheck
+        id: cache-linkcheck-save
+        if: ${{ !cancelled() && github.event_name == 'schedule' }}
+        uses: actions/cache/save@v4
+        with:
+          path: book/linkcheck/cache.json
+          key: linkcheck--${{ env.MDBOOK_LINKCHECK2_VERSION }}
+
       - name: Deploy to gh-pages
         if: github.event_name == 'push'
         run: |
diff --git a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml
new file mode 100644
index 00000000000..87a3ee2e78f
--- /dev/null
+++ b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml
@@ -0,0 +1,85 @@
+name: rustc-pull
+
+on:
+  workflow_dispatch:
+  schedule:
+    # Run at 04:00 UTC every Monday
+    - cron: '0 4 * * 1'
+
+jobs:
+  pull:
+    if: github.repository == 'rust-lang/rustc-dev-guide'
+    runs-on: ubuntu-latest
+    outputs:
+      pr_url: ${{ steps.update-pr.outputs.pr_url }}
+    permissions:
+      contents: write
+      pull-requests: write
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          # We need the full history for josh to work
+          fetch-depth: '0'
+      - name: Install stable Rust toolchain
+        run: rustup update stable
+      - uses: Swatinem/rust-cache@v2
+        with:
+          workspaces: "josh-sync"
+          # Cache the josh directory with checked out rustc
+          cache-directories: "/home/runner/.cache/rustc-dev-guide-josh"
+      - name: Install josh
+        run: RUSTFLAGS="--cap-lints warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04
+      - name: Setup bot git name and email
+        run: |
+          git config --global user.name 'The rustc-dev-guide Cronjob Bot'
+          git config --global user.email 'github-actions@github.com'
+      - name: Perform rustc-pull
+        run: cargo run --manifest-path josh-sync/Cargo.toml -- rustc-pull
+      - name: Push changes to a branch
+        run: |
+          # Update a sticky branch that is used only for rustc pulls
+          BRANCH="rustc-pull"
+          git switch -c $BRANCH
+          git push -u origin $BRANCH --force
+      - name: Create pull request
+        id: update-pr
+        run: |
+          # Check if an open pull request for an rustc pull update already exists
+          # If it does, the previous push has just updated it
+          # If not, we create it now
+          RESULT=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | length' --json title`
+          if [[ "$RESULT" -eq 0 ]]; then
+            echo "Creating new pull request"
+            PR_URL=gh pr create -B master --title 'Rustc pull update' --body 'Latest update from rustc.'
+            echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
+          else
+            PR_URL=gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].url' --json url,title
+            echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
+          fi
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+  send-zulip-message:
+    needs: [pull]
+    if: ${{ !cancelled() }}
+    runs-on: ubuntu-latest
+    steps:
+      - name: Compute message
+        id: message
+        run: |
+          if [ "${{ needs.pull.result }}" == "failure" ];
+          then
+            WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+            echo "message=Rustc pull sync failed. Check out the [workflow URL]($WORKFLOW_URL)." >> $GITHUB_OUTPUT
+          else
+            echo "message=Rustc pull sync succeeded. Check out the [PR](${{ needs.pull.outputs.pr_url }})." >> $GITHUB_OUTPUT
+          fi
+      - name: Send a Zulip message about updated PR
+        uses: zulip/github-actions-zulip/send-message@e4c8f27c732ba9bd98ac6be0583096dea82feea5
+        with:
+          api-key: ${{ secrets.ZULIP_API_TOKEN }}
+          email: "rustc-dev-guide-gha-notif-bot@rust-lang.zulipchat.com"
+          organization-url: "https://rust-lang.zulipchat.com"
+          to: 196385
+          type: "stream"
+          topic: "Subtree sync automation"
+          content: ${{ steps.message.outputs.message }}
diff --git a/src/doc/rustc-dev-guide/.gitignore b/src/doc/rustc-dev-guide/.gitignore
index 160c5f0fe5c..f03fcae753f 100644
--- a/src/doc/rustc-dev-guide/.gitignore
+++ b/src/doc/rustc-dev-guide/.gitignore
@@ -4,3 +4,5 @@ ci/date-check/target/
 
 # Generated by check-in.sh
 pulls.json
+
+josh-sync/target
diff --git a/src/doc/rustc-dev-guide/README.md b/src/doc/rustc-dev-guide/README.md
index 7ce7d4ddf3e..2464ffbbc50 100644
--- a/src/doc/rustc-dev-guide/README.md
+++ b/src/doc/rustc-dev-guide/README.md
@@ -74,6 +74,13 @@ including the `<!-- toc -->` marker at the place where you want the TOC.
 
 This repository is linked to `rust-lang/rust` as a [josh](https://josh-project.github.io/josh/intro.html) subtree. You can use the following commands to synchronize the subtree in both directions.
 
+You'll need to install `josh-proxy` locally via
+
+```
+cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04
+```
+Older versions of `josh-proxy` may not round trip commits losslessly so it is important to install this exact version.
+
 ### Pull changes from `rust-lang/rust` into this repository
 1) Checkout a new branch that will be used to create a PR into `rust-lang/rustc-dev-guide`
 2) Run the pull command
diff --git a/src/doc/rustc-dev-guide/book.toml b/src/doc/rustc-dev-guide/book.toml
index 2f67aecf6f0..67069d9930f 100644
--- a/src/doc/rustc-dev-guide/book.toml
+++ b/src/doc/rustc-dev-guide/book.toml
@@ -52,7 +52,9 @@ exclude = [
     # 500 is returned for HEAD request
     "code\\.visualstudio\\.com/docs/editor/tasks",
 ]
-cache-timeout = 86400
+# The scheduled CI runs every day and so we need to reuse a part of the cache
+# in order to face "Server returned 429 Too Many Requests" errors for github.com.
+cache-timeout = 90000
 warning-policy = "error"
 
 [output.html.redirect]
diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
index 576bbcea965..8983915d78a 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
@@ -18,8 +18,8 @@ use std::path::Path;
 
 use rustc_ast_pretty::pprust::item_to_string;
 use rustc_data_structures::sync::Lrc;
-use rustc_driver::{Compilation, RunCompiler};
-use rustc_interface::interface::Compiler;
+use rustc_driver::{Compilation, run_compiler};
+use rustc_interface::interface::{Compiler, Config};
 use rustc_middle::ty::TyCtxt;
 
 struct MyFileLoader;
@@ -51,6 +51,10 @@ fn main() {
 struct MyCallbacks;
 
 impl rustc_driver::Callbacks for MyCallbacks {
+    fn config(&mut self, config: &mut Config) {
+        config.file_loader = Some(Box::new(MyFileLoader));
+    }
+
     fn after_crate_root_parsing(
         &mut self,
         _compiler: &Compiler,
@@ -83,10 +87,5 @@ impl rustc_driver::Callbacks for MyCallbacks {
 }
 
 fn main() {
-    match RunCompiler::new(&["main.rs".to_string()], &mut MyCallbacks) {
-        mut compiler => {
-            compiler.set_file_loader(Some(Box::new(MyFileLoader)));
-            compiler.run();
-        }
-    }
+    run_compiler(&["main.rs".to_string()], &mut MyCallbacks);
 }
diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
index 90a85d5db21..c894b60444a 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
@@ -18,8 +18,8 @@ use std::path::Path;
 
 use rustc_ast_pretty::pprust::item_to_string;
 use rustc_data_structures::sync::Lrc;
-use rustc_driver::{Compilation, RunCompiler};
-use rustc_interface::interface::Compiler;
+use rustc_driver::{Compilation, run_compiler};
+use rustc_interface::interface::{Compiler, Config};
 use rustc_middle::ty::TyCtxt;
 
 struct MyFileLoader;
@@ -51,6 +51,10 @@ fn main() {
 struct MyCallbacks;
 
 impl rustc_driver::Callbacks for MyCallbacks {
+    fn config(&mut self, config: &mut Config) {
+        config.file_loader = Some(Box::new(MyFileLoader));
+    }
+
     fn after_crate_root_parsing(
         &mut self,
         _compiler: &Compiler,
@@ -90,10 +94,5 @@ impl rustc_driver::Callbacks for MyCallbacks {
 }
 
 fn main() {
-    match RunCompiler::new(&["main.rs".to_string()], &mut MyCallbacks) {
-        mut compiler => {
-            compiler.set_file_loader(Some(Box::new(MyFileLoader)));
-            compiler.run();
-        }
-    }
+    run_compiler(&["main.rs".to_string()], &mut MyCallbacks);
 }
diff --git a/src/doc/rustc-dev-guide/josh-sync/src/sync.rs b/src/doc/rustc-dev-guide/josh-sync/src/sync.rs
index da21a4c9a27..eff80b1091d 100644
--- a/src/doc/rustc-dev-guide/josh-sync/src/sync.rs
+++ b/src/doc/rustc-dev-guide/josh-sync/src/sync.rs
@@ -45,6 +45,11 @@ impl GitSync {
         let josh_url =
             format!("http://localhost:{JOSH_PORT}/{UPSTREAM_REPO}.git@{commit}{JOSH_FILTER}.git");
 
+        let previous_base_commit = sh.read_file("rust-version")?.trim().to_string();
+        if previous_base_commit == commit {
+            return Err(anyhow::anyhow!("No changes since last pull"));
+        }
+
         // Update rust-version file. As a separate commit, since making it part of
         // the merge has confused the heck out of josh in the past.
         // We pass `--no-verify` to avoid running git hooks.
@@ -76,12 +81,22 @@ impl GitSync {
         };
         let num_roots_before = num_roots()?;
 
+        let sha = cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout;
+
         // Merge the fetched commit.
         const MERGE_COMMIT_MESSAGE: &str = "Merge from rustc";
         cmd!(sh, "git merge FETCH_HEAD --no-verify --no-ff -m {MERGE_COMMIT_MESSAGE}")
             .run()
             .context("FAILED to merge new commits, something went wrong")?;
 
+        let current_sha = cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout;
+        if current_sha == sha {
+            cmd!(sh, "git reset --hard HEAD^")
+                .run()
+                .expect("FAILED to clean up after creating the preparation commit");
+            return Err(anyhow::anyhow!("No merge was performed, nothing to pull. Rolled back the preparation commit."));
+        }
+
         // Check that the number of roots did not increase.
         if num_roots()? != num_roots_before {
             bail!("Josh created a new root commit. This is probably not the history you want.");
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index 876c32dcf43..9693bfd63e8 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-dcfa38fe234de9304169afc6638e81d0dd222c06
+ecda83b30f0f68cf5692855dddc0bc38ee8863fc
diff --git a/src/doc/rustc-dev-guide/src/appendix/code-index.md b/src/doc/rustc-dev-guide/src/appendix/code-index.md
index c33887d7294..b96ede68eab 100644
--- a/src/doc/rustc-dev-guide/src/appendix/code-index.md
+++ b/src/doc/rustc-dev-guide/src/appendix/code-index.md
@@ -14,17 +14,16 @@ Item            |  Kind    | Short description           | Chapter            |
 `Diag` | struct | A struct for a compiler diagnostic, such as an error or lint | [Emitting Diagnostics] | [compiler/rustc_errors/src/diagnostic.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html)
 `DocContext` | struct | A state container used by rustdoc when crawling through a crate to gather its documentation | [Rustdoc] | [src/librustdoc/core.rs](https://github.com/rust-lang/rust/blob/master/src/librustdoc/core.rs)
 `HirId` | struct | One of four types of HIR node identifiers | [Identifiers in the HIR] | [compiler/rustc_hir/src/hir_id.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir_id/struct.HirId.html)
+`Lexer` | struct | This is the lexer used during parsing. It consumes characters from the raw source code being compiled and produces a series of tokens for use by the rest of the parser | [The parser] |  [compiler/rustc_parse/src/lexer/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/lexer/struct.Lexer.html)
 `NodeId` | struct | One of four types of HIR node identifiers. Being phased out | [Identifiers in the HIR] | [compiler/rustc_ast/src/ast.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/node_id/struct.NodeId.html)
 `P` | struct | An owned immutable smart pointer. By contrast, `&T` is not owned, and `Box<T>` is not immutable. | None | [compiler/rustc_ast/src/ptr.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ptr/struct.P.html)
 `ParamEnv` | struct | Information about generic parameters or `Self`, useful for working with associated or generic items | [Parameter Environment] | [compiler/rustc_middle/src/ty/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html)
 `ParseSess` | struct | This struct contains information about a parsing session | [The parser] | [compiler/rustc_session/src/parse/parse.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/struct.ParseSess.html)
-`Query` | struct | Represents the result of query to the `Compiler` interface and allows stealing, borrowing, and returning the results of compiler passes. | [The Rustc Driver and Interface] | [compiler/rustc_interface/src/queries.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/queries/struct.Query.html)
 `Rib` | struct | Represents a single scope of names | [Name resolution] | [compiler/rustc_resolve/src/lib.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/struct.Rib.html)
 `Session` | struct | The data associated with a compilation session | [The parser], [The Rustc Driver and Interface] | [compiler/rustc_session/src/session.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/struct.Session.html)
 `SourceFile` | struct | Part of the `SourceMap`. Maps AST nodes to their source code for a single source file. Was previously called FileMap | [The parser] | [compiler/rustc_span/src/lib.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.SourceFile.html)
 `SourceMap` | struct | Maps AST nodes to their source code. It is composed of `SourceFile`s. Was previously called CodeMap | [The parser] | [compiler/rustc_span/src/source_map.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/source_map/struct.SourceMap.html)
 `Span` | struct  | A location in the user's source code, used for error reporting primarily | [Emitting Diagnostics] | [compiler/rustc_span/src/span_encoding.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html)
-`StringReader` | struct | This is the lexer used during parsing. It consumes characters from the raw source code being compiled and produces a series of tokens for use by the rest of the parser | [The parser] |  [compiler/rustc_parse/src/lexer/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/lexer/struct.StringReader.html)
 `rustc_ast::token_stream::TokenStream` | struct | An abstract sequence of tokens, organized into `TokenTree`s | [The parser], [Macro expansion] | [compiler/rustc_ast/src/tokenstream.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/tokenstream/struct.TokenStream.html)
 `TraitDef` | struct | This struct contains a trait's definition with type information | [The `ty` modules] |  [compiler/rustc_middle/src/ty/trait_def.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait_def/struct.TraitDef.html)
 `TraitRef` | struct | The combination of a trait and its input types (e.g. `P0: Trait<P1...Pn>`) | [Trait Solving: Goals and Clauses]  |  [compiler/rustc_middle/src/ty/sty.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.TraitRef.html)
diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md
index bf3475a984b..a7c3236d356 100644
--- a/src/doc/rustc-dev-guide/src/appendix/glossary.md
+++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md
@@ -69,7 +69,7 @@ Term                                                  | Meaning
 <span id="rib">rib</span>                      |  A data structure in the name resolver that keeps track of a single scope for names. ([see more](../name-resolution.md))
 <span id="rpit">RPIT</span>                    |  A return-position `impl Trait`. ([see the reference](https://doc.rust-lang.org/reference/types/impl-trait.html#abstract-return-types)).
 <span id="rpitit">RPITIT</span>                |  A return-position `impl Trait` in trait. Unlike RPIT, this is desugared to a generic associated type (GAT). Introduced in [RFC 3425](https://rust-lang.github.io/rfcs/3425-return-position-impl-trait-in-traits.html). ([see more](../return-position-impl-trait-in-trait.md))
-<span id="scrutinee">scrutinee</div>           |  A scrutinee is the expression that is matched on in `match` expressions and similar pattern matching constructs. For example, in `match x { A => 1, B => 2 }`, the expression `x` is the scrutinee.
+<span id="scrutinee">scrutinee</span>          |  A scrutinee is the expression that is matched on in `match` expressions and similar pattern matching constructs. For example, in `match x { A => 1, B => 2 }`, the expression `x` is the scrutinee.
 <span id="sess">`sess`</span>                  |  The compiler _session_, which stores global data used throughout compilation
 <span id="side-tables">side tables</span>      |  Because the [AST](#ast) and HIR are immutable once created, we often carry extra information about them in the form of hashtables, indexed by the id of a particular node.
 <span id="sigil">sigil</span>                  |  Like a keyword but composed entirely of non-alphanumeric tokens. For example, `&` is a sigil for references.
diff --git a/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md b/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md
index 3521c00f5cf..0f81d3cb48a 100644
--- a/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md
+++ b/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md
@@ -45,7 +45,7 @@ heavily on other parts of the crate. The separation of the code must not affect
 the logic of the code nor its performance.
 
 For these reasons, the separation process involves two transformations that
-have to be done at the same time for the resulting code to compile :
+have to be done at the same time for the resulting code to compile:
 
 1. replace all the LLVM-specific types by generics inside function signatures
    and structure definitions;
diff --git a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/closure_constraints.md b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/closure_constraints.md
index be279b773cf..b95c9f72306 100644
--- a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/closure_constraints.md
+++ b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/closure_constraints.md
@@ -31,9 +31,9 @@ It starts by calling `fn try_promote_type_test_subject`. This function takes the
 
 We then promote the `lower_bound` into the context of the caller. If the lower bound is equal to a placeholder, we replace it with `'static`
 
-We then look at all universal regions `uv` which are required to outlive `lower_bound`, i.e. for which borrow checking adding region constraints. For each of these we then emit a `ClosureOutlivesRequirement` for non-local universal regions which are known to outlive `uv`.
+We then look at all universal regions `uv` which are required to be outlived by `lower_bound`, i.e. for which borrow checking added region constraints. For each of these we then emit a `ClosureOutlivesRequirement` for all non-local universal regions which are known to outlive `uv`.
 
-As we've already built the region graph of the closure at this point and emitted errors if that one is inconsistent, we are also able to assume that the outlive constraints `uv: lower_bound` hold.
+As we've already built the region graph of the closure at this point and separately check that it is consistent, we are also able to assume the outlive constraints `uv: lower_bound` here.
 
 So if we have a type-outlives bounds we can't prove, e.g. `T: 'local_infer`, we use the region graph to go to universal variables `'a` with `'a: local_infer`. In case `'a` are local, we then use the assumed outlived constraints to go to non-local ones.
 
diff --git a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md
index 4857cf5e0be..e6a16df6d2a 100644
--- a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md
+++ b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md
@@ -227,7 +227,7 @@ that we use for unstable features:
 Ideally, breaking changes should have landed on the **stable branch** of the
 compiler before they are finalized.
 
-<a id="guide">
+<a id="guide"></a>
 
 ### Removing a lint
 
diff --git a/src/doc/rustc-dev-guide/src/closure.md b/src/doc/rustc-dev-guide/src/closure.md
index 718a0e5d78b..427919cd579 100644
--- a/src/doc/rustc-dev-guide/src/closure.md
+++ b/src/doc/rustc-dev-guide/src/closure.md
@@ -157,7 +157,7 @@ The other option is to step through the code using lldb or gdb.
 
 1. `rust-lldb build/host/stage1/bin/rustc test.rs`
 2. In lldb:
-    1. `b upvar.rs:134`  // Setting the breakpoint on a certain line in the upvar.rs file`
+    1. `b upvar.rs:134`  // Setting the breakpoint on a certain line in the upvar.rs file
     2. `r`  // Run the program until it hits the breakpoint
 
 Let's start with [`upvar.rs`][upvar]. This file has something called
diff --git a/src/doc/rustc-dev-guide/src/const-eval.md b/src/doc/rustc-dev-guide/src/const-eval.md
index ee0269601af..69329a3e085 100644
--- a/src/doc/rustc-dev-guide/src/const-eval.md
+++ b/src/doc/rustc-dev-guide/src/const-eval.md
@@ -17,7 +17,7 @@ Prominent examples are:
     * need to be known to check for overlapping patterns
 
 Additionally constant evaluation can be used to reduce the workload or binary
-size at runtime by precomputing complex operations at compiletime and only
+size at runtime by precomputing complex operations at compile time and only
 storing the result.
 
 All uses of constant evaluation can either be categorized as "influencing the type system"
diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md
index ad1d33265c5..9817326f07b 100644
--- a/src/doc/rustc-dev-guide/src/contributing.md
+++ b/src/doc/rustc-dev-guide/src/contributing.md
@@ -422,68 +422,8 @@ Just a few things to keep in mind:
 
 ## Issue triage
 
-Sometimes, an issue will stay open, even though the bug has been fixed.
-And sometimes, the original bug may go stale because something has changed in the meantime.
+Please see <https://forge.rust-lang.org/release/issue-triaging.html>.
 
-It can be helpful to go through older bug reports and make sure that they are still valid.
-Load up an older issue, double check that it's still true,
-and leave a comment letting us know if it is or is not.
-The [least recently updated sort][lru] is good for finding issues like this.
-
-[Thanks to `@rustbot`][rustbot], anyone can help triage issues by adding
-appropriate labels to issues that haven't been triaged yet:
-
-[lru]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc
-[rustbot]: ./rustbot.md
-
-<style>
-.label-color {
-    border-radius:0.5em;
-}
-table td:nth-child(2) {
-    white-space: nowrap;
-}
-
-</style>
-
-| Labels | Color | Description |
-|--------|-------|-------------|
-| [A-]   | <span class="label-color" style="background-color:#f7e101;">&#x2003;</span>&nbsp;Yellow | The **area** of the project an issue relates to. |
-| [B-]   | <span class="label-color" style="background-color:#d304cb;">&#x2003;</span>&nbsp;Magenta | Issues which are **blockers**. |
-| [beta-] | <span class="label-color" style="background-color:#1e76d9;">&#x2003;</span>&nbsp;Dark Blue | Tracks changes which need to be [backported to beta][beta-backport] |
-| [C-] | <span class="label-color" style="background-color:#f5f1fd;">&#x2003;</span>&nbsp;Light Purple | The **category** of an issue. |
-| [D-] | <span class="label-color" style="background-color:#c9f7a3;">&#x2003;</span>&nbsp;Mossy Green | Issues for **diagnostics**. |
-| [E-] | <span class="label-color" style="background-color:#02e10c;">&#x2003;</span>&nbsp;Green | The **experience** level necessary to fix an issue. |
-| [F-] | <span class="label-color" style="background-color:#f9c0cc;">&#x2003;</span>&nbsp;Peach | Issues for **nightly features**. |
-| [I-] | <span class="label-color" style="background-color:#e10c02;">&#x2003;</span>&nbsp;Red | The **importance** of the issue. |
-| [I-\*-nominated] | <span class="label-color" style="background-color:#e10c02;">&#x2003;</span>&nbsp;Red | The issue has been nominated for discussion at the next meeting of the corresponding team. |
-| [I-prioritize] | <span class="label-color" style="background-color:#e10c02;">&#x2003;</span>&nbsp;Red | The issue has been nominated for prioritization by the team tagged with a **T**-prefixed label. |
-| [L-] | <span class="label-color" style="background-color:#64E9CF;">&#x2003;</span>&nbsp;Teal | The relevant **lint**. |
-| [metabug] | <span class="label-color" style="background-color:#5319e7;">&#x2003;</span>&nbsp;Purple | Bugs that collect other bugs. |
-| [O-] | <span class="label-color" style="background-color:#6e6ec0;">&#x2003;</span>&nbsp;Purple Grey | The **operating system** or platform that the issue is specific to. |
-| [P-] | <span class="label-color" style="background-color:#eb6420;">&#x2003;</span>&nbsp;Orange | The issue **priority**.  These labels can be assigned by anyone that understand the issue and is able to  prioritize it, and remove the [I-prioritize] label. |
-| [regression-] | <span class="label-color" style="background-color:#e4008a;">&#x2003;</span>&nbsp;Pink | Tracks regressions from a stable release. |
-| [relnotes] | <span class="label-color" style="background-color:#fad8c7;">&#x2003;</span>&nbsp;Light Orange | Changes that should be documented in the release notes of the next release. |
-| [S-] | <span class="label-color" style="background-color:#d3dddd;">&#x2003;</span>&nbsp;Gray | Tracks the **status** of pull requests. |
-| [S-tracking-] | <span class="label-color" style="background-color:#4682b4;">&#x2003;</span>&nbsp;Steel Blue | Tracks the **status** of [tracking issues]. |
-| [stable-] | <span class="label-color" style="background-color:#00229c;">&#x2003;</span>&nbsp;Dark Blue | Tracks changes which need to be [backported to stable][stable-backport] in anticipation of a point release. |
-| [T-] | <span class="label-color" style="background-color:#bfd4f2;">&#x2003;</span>&nbsp;Blue | Denotes which **team** the issue belongs to. |
-| [WG-] | <span class="label-color" style="background-color:#c2e0c6;">&#x2003;</span>&nbsp;Green | Denotes which **working group** the issue belongs to. |
-
-
-[A-]: https://github.com/rust-lang/rust/labels?q=A
-[B-]: https://github.com/rust-lang/rust/labels?q=B
-[C-]: https://github.com/rust-lang/rust/labels?q=C
-[D-]: https://github.com/rust-lang/rust/labels?q=D
-[E-]: https://github.com/rust-lang/rust/labels?q=E
-[F-]: https://github.com/rust-lang/rust/labels?q=F
-[I-]: https://github.com/rust-lang/rust/labels?q=I
-[L-]: https://github.com/rust-lang/rust/labels?q=L
-[O-]: https://github.com/rust-lang/rust/labels?q=O
-[P-]: https://github.com/rust-lang/rust/labels?q=P
-[S-]: https://github.com/rust-lang/rust/labels?q=S
-[T-]: https://github.com/rust-lang/rust/labels?q=T
-[WG-]: https://github.com/rust-lang/rust/labels?q=WG
 [stable-]: https://github.com/rust-lang/rust/labels?q=stable
 [beta-]: https://github.com/rust-lang/rust/labels?q=beta
 [I-\*-nominated]: https://github.com/rust-lang/rust/labels?q=nominated
diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md
index 37af8121cd1..4010e90821f 100644
--- a/src/doc/rustc-dev-guide/src/conventions.md
+++ b/src/doc/rustc-dev-guide/src/conventions.md
@@ -1,4 +1,4 @@
-This file offers some tips on the coding conventions for rustc.  This
+This file offers some tips on the coding conventions for rustc. This
 chapter covers [formatting](#formatting), [coding for correctness](#cc),
 [using crates from crates.io](#cio), and some tips on
 [structuring your PR for easy review](#er).
@@ -25,6 +25,7 @@ pass the <!-- date-check: nov 2022 --> `--edition=2021` argument yourself when c
 `rustfmt` directly.
 
 [fmt]: https://github.com/rust-dev-tools/fmt-rfcs
+
 [`rustfmt`]:https://github.com/rust-lang/rustfmt
 
 ## Formatting C++ code
@@ -40,6 +41,26 @@ When modifying that code, use this command to format it:
 This uses a pinned version of `clang-format`, to avoid relying on the local
 environment.
 
+## Formatting and linting Python code
+
+The Rust repository contains quite a lof of Python code. We try to keep
+it both linted and formatted by the [ruff][ruff] tool.
+
+When modifying Python code, use this command to format it:
+```sh
+./x test tidy --extra-checks=py:fmt --bless
+```
+
+and the following command to run lints:
+```sh
+./x test tidy --extra-checks=py:lint
+```
+
+This uses a pinned version of `ruff`, to avoid relying on the local
+environment.
+
+[ruff]: https://github.com/astral-sh/ruff
+
 <a id="copyright"></a>
 
 <!-- REUSE-IgnoreStart -->
@@ -84,7 +105,7 @@ Using `_` in a match is convenient, but it means that when new
 variants are added to the enum, they may not get handled correctly.
 Ask yourself: if a new variant were added to this enum, what's the
 chance that it would want to use the `_` code, versus having some
-other treatment?  Unless the answer is "low", then prefer an
+other treatment? Unless the answer is "low", then prefer an
 exhaustive match. (The same advice applies to `if let` and `while
 let`, which are effectively tests for a single variant.)
 
@@ -124,7 +145,7 @@ See the [crates.io dependencies][crates] section.
 # How to structure your PR
 
 How you prepare the commits in your PR can make a big difference for the
-reviewer.  Here are some tips.
+reviewer. Here are some tips.
 
 **Isolate "pure refactorings" into their own commit.** For example, if
 you rename a method, then put that rename into its own commit, along
@@ -165,4 +186,5 @@ to the compiler.
   crate-related, often the spelling is changed to `krate`.
 
 [tcx]: ./ty.md
+
 [crates]: ./crates-io.md
diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md
index ccd1011659d..709e9d4f889 100644
--- a/src/doc/rustc-dev-guide/src/diagnostics.md
+++ b/src/doc/rustc-dev-guide/src/diagnostics.md
@@ -111,7 +111,7 @@ Here are a few examples:
   their crate, making this a hard error would make refactoring and development
   very painful.
 - [future-incompatible lints]:
-  these are silencable lints.
+  these are silenceable lints.
   It was decided that making them fixed errors would cause too much breakage,
   so warnings are instead emitted,
   and will eventually be turned into fixed (hard) errors.
diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md
index a7ab3d773ac..f3170c9222d 100644
--- a/src/doc/rustc-dev-guide/src/external-repos.md
+++ b/src/doc/rustc-dev-guide/src/external-repos.md
@@ -18,9 +18,11 @@ The following external projects are managed using some form of a `subtree`:
 
 * [clippy](https://github.com/rust-lang/rust-clippy)
 * [miri](https://github.com/rust-lang/miri)
+* [portable-simd](https://github.com/rust-lang/portable-simd)
 * [rustfmt](https://github.com/rust-lang/rustfmt)
 * [rust-analyzer](https://github.com/rust-lang/rust-analyzer)
 * [rustc_codegen_cranelift](https://github.com/rust-lang/rustc_codegen_cranelift)
+* [rustc-dev-guide](https://github.com/rust-lang/rustc-dev-guide)
 
 In contrast to `submodule` dependencies
 (see below for those), the `subtree` dependencies are just regular files and directories which can
@@ -33,13 +35,15 @@ implement a new tool feature or test, that should happen in one collective rustc
 
 * Using `git subtree`
   * `clippy` ([sync guide](https://doc.rust-lang.org/nightly/clippy/development/infrastructure/sync.html#performing-the-sync-from-rust-langrust-to-clippy))
+  * `portable-simd` ([sync script](https://github.com/rust-lang/portable-simd/blob/master/subtree-sync.sh))
   * `rustfmt`
   * `rustc_codegen_cranelift` ([sync script](https://github.com/rust-lang/rustc_codegen_cranelift/blob/113af154d459e41b3dc2c5d7d878e3d3a8f33c69/scripts/rustup.sh#L7))
 * Using the [josh] tool
   * `miri` ([sync guide](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#advanced-topic-syncing-with-the-rustc-repo))
   * `rust-analyzer` ([sync script](https://github.com/rust-lang/rust-analyzer/blob/2e13684be123eca7181aa48e043e185d8044a84a/xtask/src/release.rs#L147))
+  * `rustc-dev-guide` ([sync guide](https://github.com/rust-lang/rustc-dev-guide#synchronizing-josh-subtree-with-rustc))
 
-The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. Specific tooling is required to work with josh, you can check out the `miri` or `rust-analyzer` scripts linked above for inspiration. If you want to migrate a subtree from `git subtree` to josh, you can check out [this guide](https://hackmd.io/7pOuxnkdQDaL1Y1FQr65xg).
+The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. Specific tooling is required to work with josh, you can check out the `miri` or `rust-analyzer` scripts linked above for inspiration. If you want to migrate a repository dependency from `git subtree` or `git submodule` to josh, you can check out [this guide](https://hackmd.io/7pOuxnkdQDaL1Y1FQr65xg).
 
 Below you can find a guide on how to perform push and pull synchronization with the main rustc repo using `git subtree`, although these instructions might differ repo from repo.
 
diff --git a/src/doc/rustc-dev-guide/src/guides/editions.md b/src/doc/rustc-dev-guide/src/guides/editions.md
index 336e391df12..ea207167791 100644
--- a/src/doc/rustc-dev-guide/src/guides/editions.md
+++ b/src/doc/rustc-dev-guide/src/guides/editions.md
@@ -91,7 +91,7 @@ stability.
 ## Edition parsing
 
 For the most part, the lexer is edition-agnostic.
-Within [`StringReader`], tokens can be modified based on edition-specific behavior.
+Within [`Lexer`], tokens can be modified based on edition-specific behavior.
 For example, C-String literals like `c"foo"` are split into multiple tokens in editions before 2021.
 This is also where things like reserved prefixes are handled for the 2021 edition.
 
@@ -114,7 +114,7 @@ For example, the deprecated `start...end` pattern syntax emits the
 [`ellipsis_inclusive_range_patterns`] lint on editions before 2021, and in 2021 is an hard error via
 the `emit_err` method.
 
-[`StringReader`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/lexer/struct.StringReader.html
+[`Lexer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/lexer/struct.Lexer.html
 [`ParseSess::edition`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/struct.ParseSess.html#structfield.edition
 [`ellipsis_inclusive_range_patterns`]: https://doc.rust-lang.org/nightly/rustc/lints/listing/warn-by-default.html#ellipsis-inclusive-range-patterns
 
diff --git a/src/doc/rustc-dev-guide/src/opaque-types-impl-trait-inference.md b/src/doc/rustc-dev-guide/src/opaque-types-impl-trait-inference.md
index c56d51a4bb7..bdf4e4cd870 100644
--- a/src/doc/rustc-dev-guide/src/opaque-types-impl-trait-inference.md
+++ b/src/doc/rustc-dev-guide/src/opaque-types-impl-trait-inference.md
@@ -78,7 +78,7 @@ If that fails, we reveal the hidden type of the opaque type,
 but only to prove this specific trait bound, not in general.
 Revealing is done by invoking the `type_of` query on the `DefId` of the opaque type.
 The query will internally request the hidden types from the defining function(s)
-and return that (see [the section on `type_of`](#Within-the-type_of-query) for more details).
+and return that (see [the section on `type_of`](#within-the-type_of-query) for more details).
 
 #### Flowchart of type checking steps
 
diff --git a/src/doc/rustc-dev-guide/src/overview.md b/src/doc/rustc-dev-guide/src/overview.md
index cc17eaa9e48..21ab0040646 100644
--- a/src/doc/rustc-dev-guide/src/overview.md
+++ b/src/doc/rustc-dev-guide/src/overview.md
@@ -38,7 +38,7 @@ Unicode character encoding.
 
 The token stream passes through a higher-level lexer located in
 [`rustc_parse`] to prepare for the next stage of the compile process. The
-[`StringReader`] `struct` is used at this stage to perform a set of validations
+[`Lexer`] `struct` is used at this stage to perform a set of validations
 and turn strings into interned symbols (_interning_ is discussed later).
 [String interning] is a way of storing only one immutable
 copy of each distinct string value.
@@ -153,7 +153,7 @@ the final binary.
 [`rustc_parse::parser::Parser`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/struct.Parser.html
 [`rustc_parse`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html
 [`simplify_try`]: https://github.com/rust-lang/rust/pull/66282
-[`StringReader`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/lexer/struct.StringReader.html
+[`Lexer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/lexer/struct.Lexer.html
 [`Ty<'tcx>`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html
 [borrow checking]: borrow_check.md
 [codegen]: backend/codegen.md
diff --git a/src/doc/rustc-dev-guide/src/rustc-driver/intro.md b/src/doc/rustc-dev-guide/src/rustc-driver/intro.md
index a6234dc129f..40500e6bc7a 100644
--- a/src/doc/rustc-dev-guide/src/rustc-driver/intro.md
+++ b/src/doc/rustc-dev-guide/src/rustc-driver/intro.md
@@ -6,7 +6,7 @@ The [`rustc_driver`] is essentially `rustc`'s `main` function.
 It acts as the glue for running the various phases of the compiler in the correct order,
 using the interface defined in the [`rustc_interface`] crate. Where possible, using [`rustc_driver`] rather than [`rustc_interface`] is recommended.
 
-The main entry point of [`rustc_driver`] is [`rustc_driver::RunCompiler`][rd_rc].
+The main entry point of [`rustc_driver`] is [`rustc_driver::run_compiler`][rd_rc].
 This builder accepts the same command-line args as rustc as well as an implementation of [`Callbacks`][cb] and a couple of other optional options.
 [`Callbacks`][cb] is a `trait` that allows for custom compiler configuration,
 as well as allowing custom code to run after different phases of the compilation.
@@ -40,7 +40,7 @@ specifically [`rustc_driver_impl::run_compiler`][rdi_rc]
 [cb]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html
 [example]: https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-interface-example.rs
 [i_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/fn.run_compiler.html
-[rd_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/struct.RunCompiler.html
+[rd_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/fn.run_compiler.html
 [rdi_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver_impl/fn.run_compiler.html
 [stupid-stats]: https://github.com/nrc/stupid-stats
 [`nightly-rustc`]: https://doc.rust-lang.org/nightly/nightly-rustc/
diff --git a/src/doc/rustc-dev-guide/src/solve/caching.md b/src/doc/rustc-dev-guide/src/solve/caching.md
index 72b90c59bee..e568d47ca25 100644
--- a/src/doc/rustc-dev-guide/src/solve/caching.md
+++ b/src/doc/rustc-dev-guide/src/solve/caching.md
@@ -98,8 +98,8 @@ TODO: write this :3
 [req-depth-ck]: https://github.com/rust-lang/rust/blob/7606c13961ddc1174b70638e934df0439b7dc515/compiler/rustc_middle/src/traits/solve/cache.rs#L76-L86
 [update-depth]: https://github.com/rust-lang/rust/blob/7606c13961ddc1174b70638e934df0439b7dc515/compiler/rustc_trait_selection/src/solve/search_graph.rs#L308
 [rem-depth]: https://github.com/rust-lang/rust/blob/7606c13961ddc1174b70638e934df0439b7dc515/compiler/rustc_middle/src/traits/solve/cache.rs#L124
-[^1]: This is overly restrictive: if all nested goal return the overflow response with some
-availabledepth `n`, then their result should be the same for any depths smaller than `n`.
+[^1]: This is overly restrictive: if all nested goals return the overflow response with some
+available depth `n`, then their result should be the same for any depths smaller than `n`.
 We can implement this optimization in the future.
 
 [chapter on coinduction]: ./coinduction.md
diff --git a/src/doc/rustc-dev-guide/src/solve/invariants.md b/src/doc/rustc-dev-guide/src/solve/invariants.md
index c16a3aeb2b3..fd12b195757 100644
--- a/src/doc/rustc-dev-guide/src/solve/invariants.md
+++ b/src/doc/rustc-dev-guide/src/solve/invariants.md
@@ -23,9 +23,6 @@ well-formed after normalizing said aliases. We rely on this as
 otherwise we would have to re-check for well-formedness for these
 types.
 
-This is unfortunately broken for `<fndef as FnOnce<..>>::Output` due to implied bounds,
-resulting in [#114936].
-
 ### Structural equality modulo regions implies semantic equality ✅
 
 If you have a some type and equate it to itself after replacing any regions with unique
@@ -33,7 +30,7 @@ inference variables in both the lhs and rhs, the now potentially structurally di
 types should still be equal to each other.
 
 Needed to prevent goals from succeeding in HIR typeck and then failing in MIR borrowck.
-If this does invariant is broken MIR typeck ends up failing with an ICE.
+If this invariant is broken MIR typeck ends up failing with an ICE.
 
 ### Applying inference results from a goal does not change its result ❌
 
@@ -91,7 +88,7 @@ it can easily result in unsoundness, e.g. [#57893](https://github.com/rust-lang/
 
 If a trait goal holds with an empty environment, there should be a unique `impl`,
 either user-defined or builtin, which is used to prove that goal. This is
-necessary to select a unique method. It 
+necessary to select a unique method.
 
 We do however break this invariant in few cases, some of which are due to bugs,
 some by design:
diff --git a/src/doc/rustc-dev-guide/src/solve/the-solver.md b/src/doc/rustc-dev-guide/src/solve/the-solver.md
index f7d82d117a0..006fb649d22 100644
--- a/src/doc/rustc-dev-guide/src/solve/the-solver.md
+++ b/src/doc/rustc-dev-guide/src/solve/the-solver.md
@@ -25,7 +25,7 @@ a separate "probe", to not leak inference constraints to the other candidates.
 We then try to merge the assembled candidates via `EvalCtxt::merge_candidates`.
 
 
-## Important concepts and design pattern
+## Important concepts and design patterns
 
 ### `EvalCtxt::add_goal`
 
@@ -64,7 +64,7 @@ eagerly instantiates `'a` with a placeholder and then recursively proves
 Some goals can be proven in multiple ways. In these cases we try each option in
 a separate "probe" and then attempt to merge the resulting responses by using
 `EvalCtxt::try_merge_responses`. If merging the responses fails, we use
-`EvalCtxt::flounder` instead, returning ambiguity. For some goals, we try
+`EvalCtxt::flounder` instead, returning ambiguity. For some goals, we try to
 incompletely prefer some choices over others in case `EvalCtxt::try_merge_responses`
 fails.
 
diff --git a/src/doc/rustc-dev-guide/src/stability.md b/src/doc/rustc-dev-guide/src/stability.md
index 1bfe911c900..230925252ba 100644
--- a/src/doc/rustc-dev-guide/src/stability.md
+++ b/src/doc/rustc-dev-guide/src/stability.md
@@ -34,7 +34,8 @@ Previously, due to a [rustc bug], stable items inside unstable modules were
 available to stable code in that location.
 As of <!-- date-check --> September 2024, items with [accidentally stabilized
 paths] are marked with the `#[rustc_allowed_through_unstable_modules]` attribute
-to prevent code dependent on those paths from breaking.
+to prevent code dependent on those paths from breaking. Do *not* add this attribute
+to any more items unless that is needed to avoid breaking changes.
 
 The `unstable` attribute may also have the `soft` value, which makes it a
 future-incompatible deny-by-default lint instead of a hard error. This is used
diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md
index 0ad1d2a28ed..9dde407895e 100644
--- a/src/doc/rustc-dev-guide/src/tests/ci.md
+++ b/src/doc/rustc-dev-guide/src/tests/ci.md
@@ -28,7 +28,7 @@ Our CI is primarily executed on [GitHub Actions], with a single workflow defined
 in [`.github/workflows/ci.yml`], which contains a bunch of steps that are
 unified for all CI jobs that we execute. When a commit is pushed to a
 corresponding branch or a PR, the workflow executes the
-[`ci.py`] script, which dynamically generates the specific CI
+[`src/ci/github-actions/ci.py`] script, which dynamically generates the specific CI
 jobs that should be executed. This script uses the [`jobs.yml`] file as an
 input, which contains a declarative configuration of all our CI jobs.
 
@@ -409,10 +409,25 @@ To learn more about the dashboard, see the [Datadog CI docs].
 [Datadog CI docs]: https://docs.datadoghq.com/continuous_integration/
 [public dashboard]: https://p.datadoghq.com/sb/3a172e20-e9e1-11ed-80e3-da7ad0900002-b5f7bb7e08b664a06b08527da85f7e30
 
+## Determining the CI configuration
+
+If you want to determine which `config.toml` settings are used in CI for a
+particular job, it is probably easiest to just look at the build log. To do
+this:
+
+1. Go to
+   <https://github.com/rust-lang-ci/rust/actions?query=branch%3Aauto+is%3Asuccess>
+   to find the most recently successful build, and click on it.
+2. Choose the job you are interested in on the left-hand side.
+3. Click on the gear icon and choose "View raw logs"
+4. Search for the string "Configure the build"
+5. All of the build settings are listed below that starting with the
+   `configure:` prefix.
+
 [GitHub Actions]: https://github.com/rust-lang/rust/actions
 [`jobs.yml`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/jobs.yml
 [`.github/workflows/ci.yml`]: https://github.com/rust-lang/rust/blob/master/.github/workflows/ci.yml
-[`ci.py`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/ci.py
+[`src/ci/github-actions/ci.py`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/ci.py
 [rust-lang-ci]: https://github.com/rust-lang-ci/rust/actions
 [bors]: https://github.com/bors
 [homu]: https://github.com/rust-lang/homu
diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md
index 426a6ff1da5..9e0f8f9c279 100644
--- a/src/doc/rustc-dev-guide/src/tests/directives.md
+++ b/src/doc/rustc-dev-guide/src/tests/directives.md
@@ -94,7 +94,7 @@ for more details.
 | Directive                         | Explanation                                                                                                              | Supported test suites                        | Possible values                                                                         |
 |-----------------------------------|--------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|-----------------------------------------------------------------------------------------|
 | `check-run-results`               | Check run test binary `run-{pass,fail}` output snapshot                                                                  | `ui`, `crashes`, `incremental` if `run-pass` | N/A                                                                                     |
-| `error-pattern`                   | Check that output contains a specific string                                                                             | `ui`, `crashes`, `incremental` if `run-pass` | String                                                                                   |
+| `error-pattern`                   | Check that output contains a specific string                                                                             | `ui`, `crashes`, `incremental` if `run-pass` | String                                                                                  |
 | `regex-error-pattern`             | Check that output contains a regex pattern                                                                               | `ui`, `crashes`, `incremental` if `run-pass` | Regex                                                                                   |
 | `check-stdout`                    | Check `stdout` against `error-pattern`s from running test binary[^check_stdout]                                          | `ui`, `crashes`, `incremental`               | N/A                                                                                     |
 | `normalize-stderr-32bit`          | Normalize actual stderr (for 32-bit platforms) with a rule `"<raw>" -> "<normalized>"` before comparing against snapshot | `ui`, `incremental`                          | `"<RAW>" -> "<NORMALIZED>"`, `<RAW>`/`<NORMALIZED>` is regex capture and replace syntax |
@@ -176,6 +176,7 @@ settings:
 - `needs-rust-lld` — ignores if the rust lld support is not enabled (`rust.lld =
   true` in `config.toml`)
 - `needs-threads` — ignores if the target does not have threading support
+- `needs-subprocess`  — ignores if the target does not have subprocess support
 - `needs-symlink` — ignores if the target does not support symlinks. This can be
   the case on Windows if the developer did not enable privileged symlink
   permissions.
@@ -251,7 +252,7 @@ Consider writing the test as a proper incremental test instead.
 
 | Directive   | Explanation                                                  | Supported test suites                    | Possible values           |
 |-------------|--------------------------------------------------------------|------------------------------------------|---------------------------|
-| `doc-flags` | Flags passed to `rustdoc` when building the test or aux file | `rustdoc`, `js-doc-test`, `rustdoc-json` | Any valid `rustdoc` flags |
+| `doc-flags` | Flags passed to `rustdoc` when building the test or aux file | `rustdoc`, `rustdoc-js`, `rustdoc-json` | Any valid `rustdoc` flags |
 
 <!--
 **FIXME(rustdoc)**: what does `check-test-line-numbers-match` do?
diff --git a/src/doc/rustc-dev-guide/src/the-parser.md b/src/doc/rustc-dev-guide/src/the-parser.md
index 703ef27941e..60a71ae3873 100644
--- a/src/doc/rustc-dev-guide/src/the-parser.md
+++ b/src/doc/rustc-dev-guide/src/the-parser.md
@@ -52,7 +52,7 @@ the token stream, and then execute the parser to get a [`Crate`] (the root AST
 node).
 
 To minimize the amount of copying that is done,
-both [`StringReader`] and [`Parser`] have lifetimes which bind them to the parent [`ParseSess`].
+both [`Lexer`] and [`Parser`] have lifetimes which bind them to the parent [`ParseSess`].
 This contains all the information needed while parsing, as well as the [`SourceMap`] itself.
 
 Note that while parsing, we may encounter macro definitions or invocations.
@@ -67,7 +67,7 @@ Code for lexical analysis is split between two crates:
   constituting tokens. Although it is popular to implement lexers as generated
   finite state machines, the lexer in [`rustc_lexer`] is hand-written.
 
-- [`StringReader`] integrates [`rustc_lexer`] with data structures specific to
+- [`Lexer`] integrates [`rustc_lexer`] with data structures specific to
   `rustc`. Specifically, it adds `Span` information to tokens returned by
   [`rustc_lexer`] and interns identifiers.
 
@@ -76,7 +76,7 @@ Code for lexical analysis is split between two crates:
 [`ParseSess`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/struct.ParseSess.html
 [`rustc_lexer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lexer/index.html
 [`SourceMap`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/source_map/struct.SourceMap.html
-[`StringReader`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/lexer/struct.StringReader.html
+[`Lexer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/lexer/struct.Lexer.html
 [ast module]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/index.html
 [ast]: ./ast-validation.md
 [parser]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/index.html
diff --git a/src/doc/rustc-dev-guide/src/traits/implied-bounds.md b/src/doc/rustc-dev-guide/src/traits/implied-bounds.md
index 911553ad3df..63b09a43f47 100644
--- a/src/doc/rustc-dev-guide/src/traits/implied-bounds.md
+++ b/src/doc/rustc-dev-guide/src/traits/implied-bounds.md
@@ -41,7 +41,7 @@ requirements of impls and functions as explicit predicates.
 
 These bounds are not added to the `ParamEnv` of the affected item itself. For lexical
 region resolution they are added using [`fn OutlivesEnvironment::with_bounds`].
-Similarly,during MIR borrowck we add them using
+Similarly, during MIR borrowck we add them using
 [`fn UniversalRegionRelationsBuilder::add_implied_bounds`].
 
 [We add implied bounds for the function signature and impl header in MIR borrowck][mir].
@@ -81,4 +81,4 @@ This results in multiple unsoundnesses:
 
 [#25860]: https://github.com/rust-lang/rust/issues/25860
 [#84591]: https://github.com/rust-lang/rust/issues/84591
-[#100051]: https://github.com/rust-lang/rust/issues/100051
\ No newline at end of file
+[#100051]: https://github.com/rust-lang/rust/issues/100051
diff --git a/src/doc/rustc-dev-guide/src/ty_module/binders.md b/src/doc/rustc-dev-guide/src/ty_module/binders.md
index 6f31103d7f3..defb7cde514 100644
--- a/src/doc/rustc-dev-guide/src/ty_module/binders.md
+++ b/src/doc/rustc-dev-guide/src/ty_module/binders.md
@@ -16,7 +16,7 @@ Usages of these parameters is represented by the `RegionKind::Bound` (or `TyKind
 - A [`BoundVar`] which specifies which of the parameters the `Binder` introduces we are referring to.
 - We also sometimes store some extra information for diagnostics reasons via the [`BoundTyKind`]/[`BoundRegionKind`] but this is not important for type equality or more generally the semantics of `Ty`. (omitted from the above example)
 
-In debug output (and also informally when talking to eachother) we tend to write these bound variables in the format of `^DebruijnIndex_BoundVar`. The above example would instead be written as `Binder(fn(&'^0_0), &[BoundVariableKind::Region])`. Sometimes when the `DebruijnIndex` is `0` we just omit it and would write `^0`.
+In debug output (and also informally when talking to each other) we tend to write these bound variables in the format of `^DebruijnIndex_BoundVar`. The above example would instead be written as `Binder(fn(&'^0_0), &[BoundVariableKind::Region])`. Sometimes when the `DebruijnIndex` is `0` we just omit it and would write `^0`.
 
 Another concrete example, this time a mixture of `for<'a>` in a where clause and a type:
 ```
diff --git a/src/doc/rustc-dev-guide/src/ty_module/early_binder.md b/src/doc/rustc-dev-guide/src/ty_module/early_binder.md
index e8ff3a53078..d83d73c955b 100644
--- a/src/doc/rustc-dev-guide/src/ty_module/early_binder.md
+++ b/src/doc/rustc-dev-guide/src/ty_module/early_binder.md
@@ -48,7 +48,7 @@ fn bar(foo: Foo<u32, f32>) {
 In the compiler the `instantiate` call for this is done in [`FieldDef::ty`] ([src][field_def_ty_src]), at some point during type checking `bar` we will wind up calling `FieldDef::ty(x, &[u32, f32])` in order to obtain the type of `foo.x`.
 
 **Note on indices:** It is a bug if the index of a `Param` does not match what the `EarlyBinder` binds. For
-example, if the index is out of bounds or the index index of a lifetime corresponds to a type parameter.
+example, if the index is out of bounds or the index of a lifetime corresponds to a type parameter.
 These sorts of errors are caught earlier in the compiler during name resolution where we disallow references
 to generics parameters introduced by items that should not be nameable by the inner item. 
 
diff --git a/src/doc/rustc-dev-guide/src/ty_module/param_ty_const_regions.md b/src/doc/rustc-dev-guide/src/ty_module/param_ty_const_regions.md
index 6b467724f49..c52f0c0df2a 100644
--- a/src/doc/rustc-dev-guide/src/ty_module/param_ty_const_regions.md
+++ b/src/doc/rustc-dev-guide/src/ty_module/param_ty_const_regions.md
@@ -53,7 +53,7 @@ Concretely given the `ty::Generics` for the item the parameter is defined on, if
 
 The index fully defines the `Ty` and is the only part of `TyKind::Param` that matters for reasoning about the code we are compiling. 
 
-Generally we do not care what the name is and only use the index is included for diagnostics and debug logs as otherwise it would be
+Generally we do not care what the name is and only use the index. The name is included for diagnostics and debug logs as otherwise it would be
 incredibly difficult to understand the output, i.e. `Vec<Param(0)>: Sized` vs `Vec<T>: Sized`. In debug output, parameter types are
 often printed out as `{name}/#{index}`, for example in the function `foo` if we were to debug print `Vec<T>` it would be written as `Vec<T/#0>`.
 
@@ -65,7 +65,7 @@ The rules against shadowing make this difficult but those language rules could c
 
 ### Lifetime parameters
 
-In contrast to `Ty`/`Const`'s `Param` singular `Param` variant, lifetimes have two variants for representing region parameters: [`RegionKind::EarlyParam`] and [`RegionKind::LateParam`]. The reason for this is due to function's distinguishing between [early and late bound parameters](../early-late-bound-params/early-late-bound-summary.md) which is discussed in an earlier chapter (see link).
+In contrast to `Ty`/`Const`'s `Param` singular `Param` variant, lifetimes have two variants for representing region parameters: [`RegionKind::EarlyParam`] and [`RegionKind::LateParam`]. The reason for this is due to function's distinguishing between [early and late bound parameters][ch_early_late_bound] which is discussed in an earlier chapter (see link).
 
 `RegionKind::EarlyParam` is structured identically to `Ty/Const`'s `Param` variant, it is simply a `u32` index and a `Symbol`. For lifetime parameters defined on non-function items we always use `ReEarlyParam`. For functions we use `ReEarlyParam` for any early bound parameters and `ReLateParam` for any late bound parameters. Note that just like `Ty` and `Const` params we often debug format them as `'SYMBOL/#INDEX`, see for example:
 
@@ -85,7 +85,7 @@ fn foo<'a, 'b, T: 'a>(one: T, two: &'a &'b u32) -> &'b u32 {
 
 `RegionKind::LateParam` will be discussed more in the chapter on [instantiating binders][ch_instantiating_binders].
 
-[ch_early_late_bound]: ../early-late-bound-params/early-late-bound-summary.md
+[ch_early_late_bound]: ../early_late_parameters.md
 [ch_binders]: ./binders.md
 [ch_instantiating_binders]: ./instantiating_binders.md
 [`BoundRegionKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.BoundRegionKind.html
diff --git a/src/doc/rustc-dev-guide/triagebot.toml b/src/doc/rustc-dev-guide/triagebot.toml
index ccb0de862ef..12aa0b7b8ff 100644
--- a/src/doc/rustc-dev-guide/triagebot.toml
+++ b/src/doc/rustc-dev-guide/triagebot.toml
@@ -6,3 +6,6 @@ allow-unauthenticated = [
     "waiting-on-author",
     "blocked",
 ]
+
+# Automatically close and reopen PRs made by bots to run CI on them
+[bot-pull-requests]
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index deeabd810d3..a706926f743 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -260,6 +260,7 @@ target | std | host | notes
 [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD
 [`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? |  | ARM64 QNX Neutrino 7.0 RTOS |
 [`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ |  | ARM64 QNX Neutrino 7.1 RTOS |
+[`aarch64-unknown-nuttx`](platform-support/nuttx.md) | * |  | ARM64 with NuttX
 [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD
 [`aarch64-unknown-redox`](platform-support/redox.md) | ✓ |  | ARM64 Redox OS
 [`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? |  | ARM64 TEEOS |
@@ -295,6 +296,8 @@ target | std | host | notes
 [`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | Armv7-A Apple WatchOS
 [`armv7s-apple-ios`](platform-support/apple-ios.md) | ✓ |  | Armv7-A Apple-A6 Apple iOS
 [`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * |  | Bare Armv8-R, hardfloat
+[`armv7a-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv7-A with NuttX
+[`armv7a-nuttx-eabihf`](platform-support/nuttx.md) | * |  | ARMv7-A with NuttX, hardfloat
 `avr-unknown-gnu-atmega328` | * |  | AVR. Requires `-Z build-std=core`
 `bpfeb-unknown-none` | * |  | BPF (big endian)
 `bpfel-unknown-none` | * |  | BPF (little endian)
@@ -389,6 +392,8 @@ target | std | host | notes
 [`thumbv6m-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv6M with NuttX
 `thumbv7a-pc-windows-msvc` |  |  |
 [`thumbv7a-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) |  |  |
+[`thumbv7a-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv7-A with NuttX
+[`thumbv7a-nuttx-eabihf`](platform-support/nuttx.md) | * |  | ARMv7-A with NuttX, hardfloat
 [`thumbv7em-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv7EM with NuttX
 [`thumbv7em-nuttx-eabihf`](platform-support/nuttx.md) | * |  | ARMv7EM with NuttX, hardfloat
 [`thumbv7m-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv7M with NuttX
diff --git a/src/doc/rustc/src/platform-support/nuttx.md b/src/doc/rustc/src/platform-support/nuttx.md
index 433a092aab2..f76fe0887b5 100644
--- a/src/doc/rustc/src/platform-support/nuttx.md
+++ b/src/doc/rustc/src/platform-support/nuttx.md
@@ -20,8 +20,13 @@ The target name follow this format: `ARCH[-VENDOR]-nuttx-ABI`, where `ARCH` is t
 
 The following target names are defined:
 
-- `thumbv6m-nuttx-eal`
-- `thumbv7m-nuttx-eal`
+- `aarch64-unknown-nuttx`
+- `armv7a-nuttx-eabi`
+- `armv7a-nuttx-eabihf`
+- `thumbv6m-nuttx-eabi`
+- `thumbv7a-nuttx-eabi`
+- `thumbv7a-nuttx-eabihf`
+- `thumbv7m-nuttx-eabi`
 - `thumbv7em-nuttx-eabi`
 - `thumbv7em-nuttx-eabihf`
 - `thumbv8m.base-nuttx-eabi`
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index fbd934bf718..7853e311a04 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1747,9 +1747,9 @@ fn maybe_expand_private_type_alias<'tcx>(
     };
     let hir::ItemKind::TyAlias(ty, generics) = alias else { return None };
 
-    let provided_params = &path.segments.last().expect("segments were empty");
+    let final_seg = &path.segments.last().expect("segments were empty");
     let mut args = DefIdMap::default();
-    let generic_args = provided_params.args();
+    let generic_args = final_seg.args();
 
     let mut indices: hir::GenericParamCount = Default::default();
     for param in generics.params.iter() {
@@ -1781,7 +1781,7 @@ fn maybe_expand_private_type_alias<'tcx>(
                 let type_ = generic_args.args.iter().find_map(|arg| match arg {
                     hir::GenericArg::Type(ty) => {
                         if indices.types == j {
-                            return Some(*ty);
+                            return Some(ty.as_unambig_ty());
                         }
                         j += 1;
                         None
@@ -1843,10 +1843,13 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
             ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
         }
         TyKind::Path(_) => clean_qpath(ty, cx),
-        TyKind::TraitObject(bounds, lifetime, _) => {
+        TyKind::TraitObject(bounds, lifetime) => {
             let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
-            let lifetime =
-                if !lifetime.is_elided() { Some(clean_lifetime(lifetime, cx)) } else { None };
+            let lifetime = if !lifetime.is_elided() {
+                Some(clean_lifetime(lifetime.pointer(), cx))
+            } else {
+                None
+            };
             DynTrait(bounds, lifetime)
         }
         TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
@@ -1854,7 +1857,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
             UnsafeBinder(Box::new(clean_unsafe_binder_ty(unsafe_binder_ty, cx)))
         }
         // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
-        TyKind::Infer
+        TyKind::Infer(())
         | TyKind::Err(_)
         | TyKind::Typeof(..)
         | TyKind::InferDelegation(..)
@@ -2533,8 +2536,10 @@ fn clean_generic_args<'tcx>(
                     GenericArg::Lifetime(clean_lifetime(lt, cx))
                 }
                 hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
-                hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
-                hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
+                hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty.as_unambig_ty(), cx)),
+                hir::GenericArg::Const(ct) => {
+                    GenericArg::Const(Box::new(clean_const(ct.as_unambig_ct(), cx)))
+                }
                 hir::GenericArg::Infer(_inf) => GenericArg::Infer,
             })
             .collect::<Vec<_>>()
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 0dda3466a71..ad67c2ba245 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -1,10 +1,10 @@
-use std::sync::atomic::AtomicBool;
-use std::sync::{Arc, LazyLock};
+use std::sync::LazyLock;
 use std::{io, mem};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::unord::UnordSet;
+use rustc_driver::USING_INTERNAL_FEATURES;
 use rustc_errors::TerminalUrl;
 use rustc_errors::codes::*;
 use rustc_errors::emitter::{
@@ -221,7 +221,6 @@ pub(crate) fn create_config(
         ..
     }: RustdocOptions,
     RenderOptions { document_private, .. }: &RenderOptions,
-    using_internal_features: Arc<AtomicBool>,
 ) -> rustc_interface::Config {
     // Add the doc cfg into the doc build.
     cfgs.push("doc".to_string());
@@ -316,7 +315,7 @@ pub(crate) fn create_config(
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
         ice_file: None,
-        using_internal_features,
+        using_internal_features: &USING_INTERNAL_FEATURES,
         expanded_args,
     }
 }
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 009e9662933..8c3e28ecec3 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -193,7 +193,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
         ice_file: None,
-        using_internal_features: Arc::default(),
+        using_internal_features: &rustc_driver::USING_INTERNAL_FEATURES,
         expanded_args: options.expanded_args.clone(),
     };
 
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 33166a39574..afe81937495 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -622,7 +622,7 @@ impl FromClean<clean::Type> for Type {
 impl FromClean<clean::Path> for Path {
     fn from_clean(path: clean::Path, renderer: &JsonRenderer<'_>) -> Path {
         Path {
-            name: path.last_opt().map_or(String::from(""), |s| String::from(s.as_str())),
+            path: path.whole_name(),
             id: renderer.id_from_item_default(path.def_id().into()),
             args: path.segments.last().map(|args| Box::new(args.clone().args.into_json(renderer))),
         }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index f07f8273e6c..bb954a31891 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -74,8 +74,6 @@ extern crate tikv_jemalloc_sys as jemalloc_sys;
 use std::env::{self, VarError};
 use std::io::{self, IsTerminal};
 use std::process;
-use std::sync::Arc;
-use std::sync::atomic::AtomicBool;
 
 use rustc_errors::DiagCtxtHandle;
 use rustc_interface::interface;
@@ -159,7 +157,7 @@ pub fn main() {
 
     let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
 
-    let using_internal_features = rustc_driver::install_ice_hook(
+    rustc_driver::install_ice_hook(
         "https://github.com/rust-lang/rust/issues/new\
     ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md",
         |_| (),
@@ -180,7 +178,7 @@ pub fn main() {
 
     let exit_code = rustc_driver::catch_with_exit_code(|| {
         let at_args = rustc_driver::args::raw_args(&early_dcx)?;
-        main_args(&mut early_dcx, &at_args, using_internal_features);
+        main_args(&mut early_dcx, &at_args);
         Ok(())
     });
     process::exit(exit_code);
@@ -769,11 +767,7 @@ fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> {
     Ok(())
 }
 
-fn main_args(
-    early_dcx: &mut EarlyDiagCtxt,
-    at_args: &[String],
-    using_internal_features: Arc<AtomicBool>,
-) {
+fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
     // Throw away the first argument, the name of the binary.
     // In case of at_args being empty, as might be the case by
     // passing empty argument array to execve under some platforms,
@@ -826,8 +820,7 @@ fn main_args(
         (false, Some(md_input)) => {
             let md_input = md_input.to_owned();
             let edition = options.edition;
-            let config =
-                core::create_config(input, options, &render_options, using_internal_features);
+            let config = core::create_config(input, options, &render_options);
 
             // `markdown::render` can invoke `doctest::make_test`, which
             // requires session globals and a thread pool, so we use
@@ -860,7 +853,7 @@ fn main_args(
     let scrape_examples_options = options.scrape_examples_options.clone();
     let bin_crate = options.bin_crate;
 
-    let config = core::create_config(input, options, &render_options, using_internal_features);
+    let config = core::create_config(input, options, &render_options);
 
     let registered_lints = config.register_lints.is_some();
 
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index d46b0dee36c..e4628e4f837 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -598,8 +598,13 @@ impl<'tcx> Visitor<'tcx> for RustdocVisitor<'_, 'tcx> {
         // Unneeded.
     }
 
-    fn visit_infer(&mut self, _: &hir::InferArg) {
-        // Unneeded.
+    fn visit_infer(
+        &mut self,
+        _inf_id: hir::HirId,
+        _inf_span: Span,
+        _kind: hir::intravisit::InferKind<'tcx>,
+    ) -> Self::Result {
+        // Unneeded
     }
 
     fn visit_lifetime(&mut self, _: &hir::Lifetime) {
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 916f0ab3cc8..e67e17a73cb 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -30,7 +30,7 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
 /// This integer is incremented with every breaking change to the API,
 /// and is returned along with the JSON blob as [`Crate::format_version`].
 /// Consuming code should assert that this value matches the format version(s) that it supports.
-pub const FORMAT_VERSION: u32 = 38;
+pub const FORMAT_VERSION: u32 = 39;
 
 /// The root of the emitted JSON blob.
 ///
@@ -1036,16 +1036,20 @@ pub enum Type {
 /// A type that has a simple path to it. This is the kind of type of structs, unions, enums, etc.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Path {
-    /// The name of the type as declared, e.g. in
+    /// The path of the type.
+    ///
+    /// This will be the path that is *used* (not where it is defined), so
+    /// multiple `Path`s may have different values for this field even if
+    /// they all refer to the same item. e.g.
     ///
     /// ```rust
-    /// mod foo {
-    ///     struct Bar;
-    /// }
+    /// pub type Vec1 = std::vec::Vec<i32>; // path: "std::vec::Vec"
+    /// pub type Vec2 = Vec<i32>; // path: "Vec"
+    /// pub type Vec3 = std::prelude::v1::Vec<i32>; // path: "std::prelude::v1::Vec"
     /// ```
-    ///
-    /// for `foo::Bar`, this field will be `Bar`.
-    pub name: String,
+    //
+    // Example tested in ./tests/rustdoc-json/path_name.rs
+    pub path: String,
     /// The ID of the type.
     pub id: Id,
     /// Generic arguments to the type.
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index a1ca23e65ff..79fd6ffe46c 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -4,12 +4,12 @@ use clippy_utils::ty::expr_sig;
 use clippy_utils::{is_default_equivalent, path_def_id};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::intravisit::{Visitor, walk_ty};
-use rustc_hir::{Block, Expr, ExprKind, LetStmt, Node, QPath, Ty, TyKind};
+use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
+use rustc_hir::{AmbigArg, Block, Expr, ExprKind, HirId, LetStmt, Node, QPath, Ty, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
+use rustc_span::{Span, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -92,8 +92,13 @@ fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>)
 struct InferVisitor(bool);
 
 impl Visitor<'_> for InferVisitor {
-    fn visit_ty(&mut self, t: &Ty<'_>) {
-        self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..));
+    fn visit_infer(&mut self, inf_id: HirId, _inf_span: Span, _kind: InferKind<'_>) -> Self::Result {
+        self.0 = true;
+        self.visit_id(inf_id);
+    }
+
+    fn visit_ty(&mut self, t: &Ty<'_, AmbigArg>) {
+        self.0 |= matches!(t.kind, TyKind::OpaqueDef(..) | TyKind::TraitObject(..));
         if !self.0 {
             walk_ty(self, t);
         }
@@ -104,7 +109,7 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match cx.tcx.parent_hir_node(expr.hir_id) {
         Node::LetStmt(LetStmt { ty: Some(ty), .. }) => {
             let mut v = InferVisitor::default();
-            v.visit_ty(ty);
+            v.visit_ty_unambig(ty);
             !v.0
         },
         Node::Expr(Expr {
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_pointer_underscore.rs b/src/tools/clippy/clippy_lints/src/casts/as_pointer_underscore.rs
index 536126fd02b..3ab6693756f 100644
--- a/src/tools/clippy/clippy_lints/src/casts/as_pointer_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/as_pointer_underscore.rs
@@ -4,7 +4,7 @@ use rustc_middle::ty::Ty;
 
 pub fn check<'tcx>(cx: &LateContext<'tcx>, ty_into: Ty<'_>, cast_to_hir: &'tcx rustc_hir::Ty<'tcx>) {
     if let rustc_hir::TyKind::Ptr(rustc_hir::MutTy { ty, .. }) = cast_to_hir.kind
-        && matches!(ty.kind, rustc_hir::TyKind::Infer)
+        && matches!(ty.kind, rustc_hir::TyKind::Infer(()))
     {
         clippy_utils::diagnostics::span_lint_and_sugg(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs b/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
index 56e894c6261..3ac486dd63f 100644
--- a/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
@@ -7,7 +7,7 @@ use rustc_middle::ty;
 use super::AS_UNDERSCORE;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ty: &'tcx Ty<'_>) {
-    if matches!(ty.kind, TyKind::Infer) {
+    if matches!(ty.kind, TyKind::Infer(())) {
         span_lint_and_then(cx, AS_UNDERSCORE, expr.span, "using `as _` conversion", |diag| {
             let ty_resolved = cx.typeck_results().expr_ty(expr);
             if let ty::Error(_) = ty_resolved.kind() {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
index 4ad39d9160d..c326a0d935c 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
@@ -38,7 +38,7 @@ pub(super) fn check(
                 return;
             };
             match cast_to_hir.kind {
-                TyKind::Infer => {
+                TyKind::Infer(()) => {
                     diag.span_suggestion_verbose(
                         expr.span,
                         "use `Into::into` instead",
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index 205357afd84..e4c0db5d9ef 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
             && let Some(generic_args) = method_path.args
             && let [GenericArg::Type(cast_to)] = generic_args.args
             // There probably is no obvious reason to do this, just to be consistent with `as` cases.
-            && !is_hir_ty_cfg_dependant(cx, cast_to)
+            && !is_hir_ty_cfg_dependant(cx, cast_to.as_unambig_ty())
         {
             let (cast_from, cast_to) = (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr));
             lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index a138ade54aa..bdc389d39dd 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -43,9 +43,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
     {
         let mut app = Applicability::MachineApplicable;
         let turbofish = match &cast_to_hir_ty.kind {
-            TyKind::Infer => String::new(),
+            TyKind::Infer(()) => String::new(),
             TyKind::Ptr(mut_ty) => {
-                if matches!(mut_ty.ty.kind, TyKind::Infer) {
+                if matches!(mut_ty.ty.kind, TyKind::Infer(())) {
                     String::new()
                 } else {
                     format!(
diff --git a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
index f699bba20ed..592c820a25e 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
@@ -34,9 +34,9 @@ pub(super) fn check<'tcx>(
 
         let mut app = Applicability::MachineApplicable;
         let turbofish = match &cast_to_hir_ty.kind {
-            TyKind::Infer => String::new(),
+            TyKind::Infer(()) => String::new(),
             TyKind::Ptr(mut_ty) => {
-                if matches!(mut_ty.ty.kind, TyKind::Infer) {
+                if matches!(mut_ty.ty.kind, TyKind::Infer(())) {
                     String::new()
                 } else {
                     format!(
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 332e897def7..9e1876e40f9 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(
                 }
             },
             // Ignore `p as *const _`
-            TyKind::Infer => return false,
+            TyKind::Infer(()) => return false,
             _ => {},
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs
index c5c4a28646d..a34af6bc226 100644
--- a/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs
@@ -18,7 +18,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_>
             Mutability::Not => ("`0 as *const _` detected", "ptr::null"),
         };
 
-        let sugg = if let TyKind::Infer = mut_ty.ty.kind {
+        let sugg = if let TyKind::Infer(()) = mut_ty.ty.kind {
             format!("{std_or_core}::{sugg_fn}()")
         } else if let Some(mut_ty_snip) = mut_ty.ty.span.get_source_text(cx) {
             format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()")
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 653726872c6..f5589d8f8e2 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -11,10 +11,10 @@ use rustc_ast::util::parser::ExprPrecedence;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{Visitor, walk_ty};
+use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
 use rustc_hir::{
-    self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat,
-    PatKind, Path, QPath, TyKind, UnOp,
+    self as hir, AmbigArg, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node,
+    Pat, PatKind, Path, QPath, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
@@ -796,7 +796,7 @@ impl TyCoercionStability {
                     if let Some(args) = path.args
                         && args.args.iter().any(|arg| match arg {
                             hir::GenericArg::Infer(_) => true,
-                            hir::GenericArg::Type(ty) => ty_contains_infer(ty),
+                            hir::GenericArg::Type(ty) => ty_contains_infer(ty.as_unambig_ty()),
                             _ => false,
                         })
                     {
@@ -815,7 +815,7 @@ impl TyCoercionStability {
                 | TyKind::Path(_) => Self::Deref,
                 TyKind::OpaqueDef(..)
                 | TyKind::TraitAscription(..)
-                | TyKind::Infer
+                | TyKind::Infer(())
                 | TyKind::Typeof(..)
                 | TyKind::TraitObject(..)
                 | TyKind::InferDelegation(..)
@@ -889,29 +889,23 @@ impl TyCoercionStability {
 fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
     struct V(bool);
     impl Visitor<'_> for V {
-        fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
-            if self.0
-                || matches!(
-                    ty.kind,
-                    TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(_) | TyKind::Err(_)
-                )
-            {
+        fn visit_infer(&mut self, inf_id: HirId, _inf_span: Span, kind: InferKind<'_>) -> Self::Result {
+            if let InferKind::Ty(_) | InferKind::Ambig(_) = kind {
                 self.0 = true;
-            } else {
-                walk_ty(self, ty);
             }
+            self.visit_id(inf_id);
         }
 
-        fn visit_generic_arg(&mut self, arg: &hir::GenericArg<'_>) {
-            if self.0 || matches!(arg, hir::GenericArg::Infer(_)) {
+        fn visit_ty(&mut self, ty: &hir::Ty<'_, AmbigArg>) {
+            if self.0 || matches!(ty.kind, TyKind::OpaqueDef(..) | TyKind::Typeof(_) | TyKind::Err(_)) {
                 self.0 = true;
-            } else if let hir::GenericArg::Type(ty) = arg {
-                self.visit_ty(ty);
+            } else {
+                walk_ty(self, ty);
             }
         }
     }
     let mut v = V(false);
-    v.visit_ty(ty);
+    v.visit_ty_unambig(ty);
     v.0
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index a78c392e208..4e8853821c3 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Diag;
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{
-    Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty,
+    AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::TyCtxt;
@@ -140,7 +140,7 @@ impl LateLintPass<'_> for DisallowedMacros {
         self.check(cx, stmt.span, None);
     }
 
-    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &Ty<'_>) {
+    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &Ty<'_, AmbigArg>) {
         self.check(cx, ty.span, None);
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index 3265404f2b2..947677e14bd 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefIdMap;
-use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
+use rustc_hir::{AmbigArg, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
         }
     }
 
-    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx, AmbigArg>) {
         if let TyKind::Path(path) = &ty.kind {
             self.check_res_emit(cx, &cx.qpath_res(path, ty.hir_id), ty.span);
         }
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index c0b4743fd71..57a30de7ad1 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -76,22 +76,22 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         if let ExprKind::MethodCall(_method, receiver, args, _) = expr.kind {
             for arg in args {
-                check_clousure(cx, Some(receiver), arg);
+                check_closure(cx, Some(receiver), arg);
             }
         }
         if let ExprKind::Call(func, args) = expr.kind {
-            check_clousure(cx, None, func);
+            check_closure(cx, None, func);
             for arg in args {
-                check_clousure(cx, None, arg);
+                check_closure(cx, None, arg);
             }
         }
     }
 }
 
 #[allow(clippy::too_many_lines)]
-fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx>>, expr: &Expr<'tcx>) {
+fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx>>, expr: &Expr<'tcx>) {
     let body = if let ExprKind::Closure(c) = expr.kind
-        && c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer))
+        && c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer(())))
         && matches!(c.fn_decl.output, FnRetTy::DefaultReturn(_))
         && !expr.span.from_expansion()
     {
diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
index d0159ab89e1..688979311c8 100644
--- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
@@ -3,10 +3,10 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
 use clippy_utils::{is_from_proc_macro, trait_ref_of_method};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty};
+use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty, walk_unambig_ty};
 use rustc_hir::{
-    BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind,
-    PredicateOrigin, Ty, WherePredicate, WherePredicateKind,
+    AmbigArg, BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item,
+    ItemKind, PredicateOrigin, Ty, WherePredicate, WherePredicateKind,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
@@ -196,7 +196,7 @@ fn bound_to_trait_def_id(bound: &GenericBound<'_>) -> Option<LocalDefId> {
 impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
+    fn visit_ty(&mut self, t: &'tcx Ty<'tcx, AmbigArg>) {
         if let Some((def_id, _)) = t.peel_refs().as_generic_param() {
             self.ty_params.remove(&def_id);
         } else {
@@ -234,7 +234,7 @@ impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> {
                 // type, any params we find nested inside of it are being used as concrete types,
                 // and can therefore can be considered used. So, we're fine to walk the left-hand
                 // side of the where bound.
-                walk_ty(self, predicate.bounded_ty);
+                walk_unambig_ty(self, predicate.bounded_ty);
             }
             for bound in predicate.bounds {
                 walk_param_bound(self, bound);
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index e43c311eb85..9a73d0c0993 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -103,7 +103,9 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
                         "replace the `Into` implementation with `From<{}>`",
                         middle_trait_ref.self_ty()
                     );
-                    if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) {
+                    if let Some(suggestions) =
+                        convert_to_from(cx, into_trait_seg, target_ty.as_unambig_ty(), self_ty, impl_item_ref)
+                    {
                         diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable);
                     } else {
                         diag.help(message);
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index ad2da3c7fcd..47a5c19215b 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -2,9 +2,8 @@ use std::borrow::Cow;
 use std::collections::BTreeMap;
 
 use rustc_errors::{Applicability, Diag};
-use rustc_hir as hir;
-use rustc_hir::intravisit::{Visitor, walk_body, walk_expr, walk_inf, walk_ty};
-use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
+use rustc_hir::intravisit::{Visitor, VisitorExt, walk_body, walk_expr, walk_ty};
+use rustc_hir::{self as hir, AmbigArg, Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
 use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
@@ -112,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
         match item.kind {
             ItemKind::Impl(impl_) => {
                 let mut vis = ImplicitHasherTypeVisitor::new(cx);
-                vis.visit_ty(impl_.self_ty);
+                vis.visit_ty_unambig(impl_.self_ty);
 
                 for target in &vis.found {
                     if !item.span.eq_ctxt(target.span()) {
@@ -159,7 +158,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
 
                 for ty in sig.decl.inputs {
                     let mut vis = ImplicitHasherTypeVisitor::new(cx);
-                    vis.visit_ty(ty);
+                    vis.visit_ty_unambig(ty);
 
                     for target in &vis.found {
                         if generics.span.from_expansion() {
@@ -287,21 +286,13 @@ impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'_, 'tcx> {
-    fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
-        if let Some(target) = ImplicitHasherType::new(self.cx, t) {
+    fn visit_ty(&mut self, t: &'tcx hir::Ty<'_, AmbigArg>) {
+        if let Some(target) = ImplicitHasherType::new(self.cx, t.as_unambig_ty()) {
             self.found.push(target);
         }
 
         walk_ty(self, t);
     }
-
-    fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
-        if let Some(target) = ImplicitHasherType::new(self.cx, &inf.to_ty()) {
-            self.found.push(target);
-        }
-
-        walk_inf(self, inf);
-    }
 }
 
 /// Looks for default-hasher-dependent constructors like `HashMap::new`.
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index ef272c305d3..d02d9b2102b 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -3,8 +3,8 @@ use clippy_utils::source::snippet;
 use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{
-    AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifiers, TyKind,
-    WherePredicateKind,
+    AmbigArg, AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifiers,
+    TyKind, WherePredicateKind,
 };
 use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
@@ -146,7 +146,9 @@ fn try_resolve_type<'tcx>(
     index: usize,
 ) -> Option<Ty<'tcx>> {
     match args.get(index - 1) {
-        Some(GenericArg::Type(ty)) => Some(lower_ty(tcx, ty)),
+        // I don't think we care about `GenericArg::Infer` since this is all for stuff in type signatures
+        // which do not permit inference variables.
+        Some(GenericArg::Type(ty)) => Some(lower_ty(tcx, ty.as_unambig_ty())),
         Some(_) => None,
         None => Some(tcx.type_of(generics.own_params[index].def_id).skip_binder()),
     }
@@ -335,7 +337,7 @@ impl<'tcx> LateLintPass<'tcx> for ImpliedBoundsInImpls {
         }
     }
 
-    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &rustc_hir::Ty<'tcx>) {
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &rustc_hir::Ty<'tcx, AmbigArg>) {
         if let TyKind::OpaqueDef(opaque_ty, ..) = ty.kind {
             check(cx, opaque_ty.bounds);
         }
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index 5a11702d7ce..2d2438514cc 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -28,7 +28,7 @@ declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
 impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
         if let Some(ty) = local.ty // Ensure that it has a type defined
-            && let TyKind::Infer = &ty.kind // that type is '_'
+            && let TyKind::Infer(()) = &ty.kind // that type is '_'
             && local.span.eq_ctxt(ty.span)
             && !in_external_macro(cx.tcx.sess, local.span)
             && !is_from_proc_macro(cx, ty)
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 239822f4085..e6761ea5c67 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -7,13 +7,13 @@ use rustc_errors::Applicability;
 use rustc_hir::FnRetTy::Return;
 use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
 use rustc_hir::intravisit::{
-    Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_param_bound, walk_poly_trait_ref,
-    walk_trait_ref, walk_ty, walk_where_predicate,
+    Visitor, VisitorExt, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_param_bound,
+    walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_unambig_ty, walk_where_predicate,
 };
 use rustc_hir::{
-    BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics,
-    HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
-    PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereBoundPredicate, WherePredicate,
+    AmbigArg, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind,
+    Generics, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node,
+    PolyTraitRef, PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereBoundPredicate, WherePredicate,
     WherePredicateKind, lang_items,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -232,11 +232,11 @@ fn could_use_elision<'tcx>(
 
     // extract lifetimes in input argument types
     for arg in func.inputs {
-        input_visitor.visit_ty(arg);
+        input_visitor.visit_ty_unambig(arg);
     }
     // extract lifetimes in output type
     if let Return(ty) = func.output {
-        output_visitor.visit_ty(ty);
+        output_visitor.visit_ty_unambig(ty);
     }
     for lt in named_generics {
         input_visitor.visit_generic_param(lt);
@@ -340,7 +340,7 @@ fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident:
         && let Some(self_ty) = func.inputs.first()
     {
         let mut visitor = RefVisitor::new(cx);
-        visitor.visit_ty(self_ty);
+        visitor.visit_ty_unambig(self_ty);
 
         !visitor.all_lts().is_empty()
     } else {
@@ -426,14 +426,14 @@ impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> {
         }
     }
 
-    fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
+    fn visit_ty(&mut self, ty: &'tcx Ty<'_, AmbigArg>) {
         match ty.kind {
             TyKind::BareFn(&BareFnTy { decl, .. }) => {
                 let mut sub_visitor = RefVisitor::new(self.cx);
                 sub_visitor.visit_fn_decl(decl);
                 self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
             },
-            TyKind::TraitObject(bounds, lt, _) => {
+            TyKind::TraitObject(bounds, lt) => {
                 if !lt.is_elided() {
                     self.unelided_trait_object_lifetime = true;
                 }
@@ -456,7 +456,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
                 // a predicate like F: Trait or F: for<'a> Trait<'a>
                 let mut visitor = RefVisitor::new(cx);
                 // walk the type F, it may not contain LT refs
-                walk_ty(&mut visitor, pred.bounded_ty);
+                walk_unambig_ty(&mut visitor, pred.bounded_ty);
                 if !visitor.all_lts().is_empty() {
                     return true;
                 }
@@ -477,8 +477,8 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
             },
             WherePredicateKind::EqPredicate(ref pred) => {
                 let mut visitor = RefVisitor::new(cx);
-                walk_ty(&mut visitor, pred.lhs_ty);
-                walk_ty(&mut visitor, pred.rhs_ty);
+                walk_unambig_ty(&mut visitor, pred.lhs_ty);
+                walk_unambig_ty(&mut visitor, pred.rhs_ty);
                 if !visitor.lts.is_empty() {
                     return true;
                 }
@@ -541,7 +541,7 @@ where
         try_visit!(self.visit_id(hir_id));
 
         self.bounded_ty_depth += 1;
-        try_visit!(self.visit_ty(bounded_ty));
+        try_visit!(self.visit_ty_unambig(bounded_ty));
         self.bounded_ty_depth -= 1;
 
         walk_list!(self, visit_param_bound, bounds);
@@ -625,7 +625,7 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
     if let Some(ref trait_ref) = impl_.of_trait {
         walk_trait_ref(&mut checker, trait_ref);
     }
-    walk_ty(&mut checker, impl_.self_ty);
+    walk_unambig_ty(&mut checker, impl_.self_ty);
     for item in impl_.items {
         walk_impl_item_ref(&mut checker, item);
     }
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index 3c669d94d69..37412866539 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet;
 use hir::def::{DefKind, Res};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
+use rustc_hir::{self as hir, AmbigArg};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
 use rustc_span::edition::Edition;
@@ -123,7 +123,7 @@ impl LateLintPass<'_> for MacroUseImports {
             self.push_unique_macro_pat_ty(cx, pat.span);
         }
     }
-    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &hir::Ty<'_>) {
+    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &hir::Ty<'_, AmbigArg>) {
         if ty.span.from_expansion() {
             self.push_unique_macro_pat_ty(cx, ty.span);
         }
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index c31656f8a05..d2a2321dae8 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -6,11 +6,11 @@ use clippy_utils::source::snippet_with_context;
 use rustc_ast::ast::LitKind;
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
+use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
-use rustc_span::sym;
+use rustc_span::{Span, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -57,13 +57,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits {
             && let ctxt = expr.span.ctxt()
             && left_expr.span.ctxt() == ctxt
             && right_expr.span.ctxt() == ctxt
-            && let Some((real_ty, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr)
+            && let Some((real_ty_span, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr)
             && matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_))
             && let ExprKind::Lit(lit) = &other_expr.kind
             && let LitKind::Int(Pu128(8), _) = lit.node
         {
             let mut app = Applicability::MachineApplicable;
-            let ty_snip = snippet_with_context(cx, real_ty.span, ctxt, "..", &mut app).0;
+            let ty_snip = snippet_with_context(cx, real_ty_span, ctxt, "..", &mut app).0;
             let sugg = create_sugg(cx, expr, format!("{ty_snip}::BITS"));
 
             span_lint_and_sugg(
@@ -85,21 +85,21 @@ fn get_one_size_of_ty<'tcx>(
     cx: &LateContext<'tcx>,
     expr1: &'tcx Expr<'_>,
     expr2: &'tcx Expr<'_>,
-) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>, &'tcx Expr<'tcx>)> {
+) -> Option<(Span, Ty<'tcx>, &'tcx Expr<'tcx>)> {
     match (get_size_of_ty(cx, expr1), get_size_of_ty(cx, expr2)) {
-        (Some((real_ty, resolved_ty)), None) => Some((real_ty, resolved_ty, expr2)),
-        (None, Some((real_ty, resolved_ty))) => Some((real_ty, resolved_ty, expr1)),
+        (Some((real_ty_span, resolved_ty)), None) => Some((real_ty_span, resolved_ty, expr2)),
+        (None, Some((real_ty_span, resolved_ty))) => Some((real_ty_span, resolved_ty, expr1)),
         _ => None,
     }
 }
 
-fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>)> {
+fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(Span, Ty<'tcx>)> {
     if let ExprKind::Call(count_func, []) = expr.kind
         && let ExprKind::Path(ref count_func_qpath) = count_func.kind
         && let QPath::Resolved(_, count_func_path) = count_func_qpath
         && let Some(segment_zero) = count_func_path.segments.first()
         && let Some(args) = segment_zero.args
-        && let Some(GenericArg::Type(real_ty)) = args.args.first()
+        && let Some(real_ty_span) = args.args.first().map(|arg| arg.span())
         && let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id()
         && cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id)
     {
@@ -107,7 +107,7 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
             .node_args(count_func.hir_id)
             .types()
             .next()
-            .map(|resolved_ty| (*real_ty, resolved_ty))
+            .map(|resolved_ty| (real_ty_span, resolved_ty))
     } else {
         None
     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index 5e58054a986..ebfd946b07e 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
                 Node::Param(..) => (),
                 Node::LetStmt(local) => {
                     let Some(ty) = local.ty else { return };
-                    if matches!(ty.kind, TyKind::Infer) {
+                    if matches!(ty.kind, TyKind::Infer(())) {
                         return;
                     }
                 },
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index b84594c0da1..1673a6f8b3a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -49,7 +49,7 @@ pub(super) fn check<'tcx>(
                         fn_decl.output,
                         FnRetTy::DefaultReturn(_)
                             | FnRetTy::Return(hir::Ty {
-                                kind: hir::TyKind::Infer,
+                                kind: hir::TyKind::Infer(()),
                                 ..
                             })
                     ) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
index 6dc8adb42df..10112b62878 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -1,14 +1,14 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res};
 use rustc_errors::Applicability;
-use rustc_hir as hir;
+use rustc_hir::{self as hir, AmbigArg};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
 
 use super::UNNECESSARY_LITERAL_UNWRAP;
 
-fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -> Option<&'a hir::Ty<'a>> {
+fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -> Option<&'a hir::Ty<'a, AmbigArg>> {
     let args = args?;
 
     if args.len() <= index {
@@ -16,10 +16,7 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -
     }
 
     match args[index] {
-        hir::GenericArg::Type(ty) => match ty.kind {
-            hir::TyKind::Infer => None,
-            _ => Some(ty),
-        },
+        hir::GenericArg::Type(ty) => Some(ty),
         _ => None,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
index 6c2ae9cc6bf..0aec26f1011 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
@@ -130,7 +130,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
 fn find_elem_explicit_type_span(fn_decl: &FnDecl<'_>) -> Option<Span> {
     if let [tuple_ty] = fn_decl.inputs
         && let TyKind::Tup([_idx_ty, elem_ty]) = tuple_ty.kind
-        && !matches!(elem_ty.kind, TyKind::Err(..) | TyKind::Infer)
+        && !matches!(elem_ty.kind, TyKind::Err(..) | TyKind::Infer(()))
     {
         Some(elem_ty.span)
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs
index e2ab5e98504..0ee851a4cf9 100644
--- a/src/tools/clippy/clippy_lints/src/mut_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_hir};
 use clippy_utils::higher;
-use rustc_hir as hir;
-use rustc_hir::intravisit;
+use rustc_hir::{self as hir, AmbigArg, intravisit};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
@@ -34,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for MutMut {
         intravisit::walk_block(&mut MutVisitor { cx }, block);
     }
 
-    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'_>) {
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'_, AmbigArg>) {
         if let hir::TyKind::Ref(_, mty) = ty.kind
             && mty.mutbl == hir::Mutability::Mut
             && let hir::TyKind::Ref(_, mty) = mty.ty.kind
diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
index 82b9d10fbeb..c3c09946c27 100644
--- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
@@ -190,7 +190,8 @@ fn in_impl<'tcx>(
         && let Some(generic_args) = seg.args
         && let Some(GenericArg::Type(other_ty)) = generic_args.args.last()
     {
-        Some((item.self_ty, other_ty))
+        // `_` is not permitted in impl headers
+        Some((item.self_ty, other_ty.as_unambig_ty()))
     } else {
         None
     }
diff --git a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
index 7d59bf24d93..074345e7532 100644
--- a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::last_path_segment;
 use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
-use rustc_hir::{GenericArg, GenericArgsParentheses, Mutability, Ty, TyKind};
+use rustc_hir::{AmbigArg, GenericArg, GenericArgsParentheses, Mutability, Ty, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
@@ -36,7 +36,7 @@ declare_clippy_lint! {
 declare_lint_pass!(RefOptionRef => [REF_OPTION_REF]);
 
 impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
-    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx, AmbigArg>) {
         if let TyKind::Ref(_, ref mut_ty) = ty.kind
             && mut_ty.mutbl == Mutability::Not
             && let TyKind::Path(qpath) = &mut_ty.ty.kind
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 99844beb8f0..790e0965198 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -10,8 +10,8 @@ use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{
-    BoundPolarity, GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment, PredicateOrigin, QPath,
-    TraitBoundModifiers, TraitItem, TraitRef, Ty, TyKind, WherePredicateKind,
+    AmbigArg, BoundPolarity, GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment,
+    PredicateOrigin, QPath, TraitBoundModifiers, TraitItem, TraitRef, Ty, TyKind, WherePredicateKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -171,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
         }
     }
 
-    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx, AmbigArg>) {
         if let TyKind::Ref(.., mut_ty) = &ty.kind
             && let TyKind::TraitObject(bounds, ..) = mut_ty.ty.kind
             && bounds.len() > 2
diff --git a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
index b2892d136fa..531422798a6 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
@@ -52,7 +52,6 @@ pub(super) fn check<'tcx>(
     let missing_generic = match args {
         Some(args) if !args.args.is_empty() => args.args.iter().any(|arg| match arg {
             GenericArg::Infer(_) => true,
-            GenericArg::Type(ty) => matches!(ty.kind, TyKind::Infer),
             _ => false,
         }),
         _ => true,
@@ -65,7 +64,7 @@ pub(super) fn check<'tcx>(
         // ... which does have type annotations.
         if let Some(ty) = local.ty
             // If this is a `let x: _ =`, we should lint.
-            && !matches!(ty.kind, TyKind::Infer)
+            && !matches!(ty.kind, TyKind::Infer(()))
         {
             return false;
         }
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
index bde88ab61ad..1a5fdf0cd64 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -25,7 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
                     _ => None,
                 })
             {
-                if is_any_trait(cx, inner) {
+                if is_any_trait(cx, inner.as_unambig_ty()) {
                     // Ignore `Box<Any>` types; see issue #1884 for details.
                     return false;
                 }
@@ -47,7 +47,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
                 // Originally reported as the issue #3128.
                 let inner_snippet = snippet(cx, inner.span, "..");
                 let suggestion = match &inner.kind {
-                    TyKind::TraitObject(bounds, lt_bound, _) if bounds.len() > 1 || !lt_bound.is_elided() => {
+                    TyKind::TraitObject(bounds, lt_bound) if bounds.len() > 1 || !lt_bound.is_elided() => {
                         format!("&{ltopt}({inner_snippet})")
                     },
                     TyKind::Path(qpath)
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 43cce625c64..391c36df492 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -560,7 +560,7 @@ impl Types {
                                     _ => None,
                                 })
                         }) {
-                            self.check_ty(cx, ty, context);
+                            self.check_ty(cx, ty.as_unambig_ty(), context);
                         }
                     },
                     QPath::Resolved(None, p) => {
@@ -574,7 +574,7 @@ impl Types {
                                     _ => None,
                                 })
                         }) {
-                            self.check_ty(cx, ty, context);
+                            self.check_ty(cx, ty.as_unambig_ty(), context);
                         }
                     },
                     QPath::TypeRelative(ty, seg) => {
@@ -585,7 +585,7 @@ impl Types {
                                 GenericArg::Type(ty) => Some(ty),
                                 _ => None,
                             }) {
-                                self.check_ty(cx, ty, context);
+                                self.check_ty(cx, ty.as_unambig_ty(), context);
                             }
                         }
                     },
diff --git a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
index b89bd6a8d05..7f51660293b 100644
--- a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint;
-use rustc_hir as hir;
-use rustc_hir::intravisit::{Visitor, walk_inf, walk_ty};
-use rustc_hir::{GenericParamKind, TyKind};
+use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
+use rustc_hir::{self as hir, AmbigArg, GenericParamKind, TyKind};
 use rustc_lint::LateContext;
+use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
 use super::TYPE_COMPLEXITY;
@@ -10,7 +10,7 @@ use super::TYPE_COMPLEXITY;
 pub(super) fn check(cx: &LateContext<'_>, ty: &hir::Ty<'_>, type_complexity_threshold: u64) -> bool {
     let score = {
         let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 };
-        visitor.visit_ty(ty);
+        visitor.visit_ty_unambig(ty);
         visitor.score
     };
 
@@ -36,15 +36,15 @@ struct TypeComplexityVisitor {
 }
 
 impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
-    fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
+    fn visit_infer(&mut self, inf_id: hir::HirId, _inf_span: Span, _kind: InferKind<'tcx>) -> Self::Result {
         self.score += 1;
-        walk_inf(self, inf);
+        self.visit_id(inf_id);
     }
 
-    fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
+    fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_, AmbigArg>) {
         let (add_score, sub_nest) = match ty.kind {
-            // _, &x and *x have only small overhead; don't mess with nesting level
-            TyKind::Infer | TyKind::Ptr(..) | TyKind::Ref(..) => (1, 0),
+            // &x and *x have only small overhead; don't mess with nesting level
+            TyKind::Ptr(..) | TyKind::Ref(..) => (1, 0),
 
             // the "normal" components of a type: named types, arrays/tuples
             TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
@@ -52,7 +52,7 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
             // function types bring a lot of overhead
             TyKind::BareFn(bare) if bare.abi == Abi::Rust => (50 * self.nest, 1),
 
-            TyKind::TraitObject(param_bounds, _, _) => {
+            TyKind::TraitObject(param_bounds, _) => {
                 let has_lifetime_parameters = param_bounds.iter().any(|bound| {
                     bound
                         .bound_generic_params
diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
index 9b236d3bda5..769244c675e 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -35,7 +35,8 @@ pub(super) fn check<'tcx>(
             && let Some(GenericArg::Type(boxed_ty)) = last.args.first()
             // extract allocator from the Box for later
             && let boxed_alloc_ty = last.args.get(1)
-            && let ty_ty = lower_ty(cx.tcx, boxed_ty)
+            // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
+            && let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty())
             && !ty_ty.has_escaping_bound_vars()
             && ty_ty.is_sized(cx.tcx, cx.typing_env())
             && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes())
@@ -55,7 +56,8 @@ pub(super) fn check<'tcx>(
                     }
                 },
                 (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) =>
-                    lower_ty(cx.tcx, l) == lower_ty(cx.tcx, r),
+                    // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
+                    lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()),
                 _ => false
             }
         {
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index d2727968c0c..660bdb9e2be 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
             return;
         }
 
-        if (local.ty.is_some_and(|ty| !matches!(ty.kind, TyKind::Infer))
+        if (local.ty.is_some_and(|ty| !matches!(ty.kind, TyKind::Infer(())))
             || matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()))
             && expr_needs_inferred_result(cx, init)
         {
@@ -158,7 +158,7 @@ fn expr_needs_inferred_result<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -
     }
     while let Some(id) = locals_to_check.pop() {
         if let Node::LetStmt(l) = cx.tcx.parent_hir_node(id) {
-            if !l.ty.is_none_or(|ty| matches!(ty.kind, TyKind::Infer)) {
+            if !l.ty.is_none_or(|ty| matches!(ty.kind, TyKind::Infer(()))) {
                 return false;
             }
             if let Some(e) = l.init {
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 05c5be03002..84b6430294f 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -7,10 +7,10 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{Visitor, walk_inf, walk_ty};
+use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
 use rustc_hir::{
-    self as hir, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl,
-    ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind,
+    self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind,
+    HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind,
 };
 use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
@@ -179,7 +179,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) {
                 if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) {
                     let mut visitor = SkipTyCollector::default();
-                    visitor.visit_ty(impl_hir_ty);
+                    visitor.visit_ty_unambig(impl_hir_ty);
                     types_to_skip.extend(visitor.types_to_skip);
                 }
             }
@@ -201,7 +201,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
         }
     }
 
-    fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &Ty<'tcx>) {
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &Ty<'tcx, AmbigArg>) {
         if !hir_ty.span.from_expansion()
             && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS)
             && let Some(&StackItem::Check {
@@ -218,7 +218,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             && let ty = if in_body > 0 {
                 cx.typeck_results().node_type(hir_ty.hir_id)
             } else {
-                lower_ty(cx.tcx, hir_ty)
+                // We don't care about ignoring infer vars here
+                lower_ty(cx.tcx, hir_ty.as_unambig_ty())
             }
             && let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity()
             && same_type_and_consts(ty, impl_ty)
@@ -275,12 +276,14 @@ struct SkipTyCollector {
 }
 
 impl Visitor<'_> for SkipTyCollector {
-    fn visit_infer(&mut self, inf: &hir::InferArg) {
-        self.types_to_skip.push(inf.hir_id);
-
-        walk_inf(self, inf);
+    fn visit_infer(&mut self, inf_id: HirId, _inf_span: Span, kind: InferKind<'_>) -> Self::Result {
+        // Conservatively assume ambiguously kinded inferred arguments are type arguments
+        if let InferKind::Ambig(_) | InferKind::Ty(_) = kind {
+            self.types_to_skip.push(inf_id);
+        }
+        self.visit_id(inf_id);
     }
-    fn visit_ty(&mut self, hir_ty: &Ty<'_>) {
+    fn visit_ty(&mut self, hir_ty: &Ty<'_, AmbigArg>) {
         self.types_to_skip.push(hir_ty.hir_id);
 
         walk_ty(self, hir_ty);
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index e14480b8655..1221abec1ab 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item};
-use rustc_hir::{self as hir, HirId, ItemKind, Node};
+use rustc_hir::{self as hir, AmbigArg, HirId, ItemKind, Node};
 use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf as _;
@@ -44,10 +44,11 @@ declare_clippy_lint! {
 declare_lint_pass!(ZeroSizedMapValues => [ZERO_SIZED_MAP_VALUES]);
 
 impl LateLintPass<'_> for ZeroSizedMapValues {
-    fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) {
+    fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx, AmbigArg>) {
         if !hir_ty.span.from_expansion()
             && !in_trait_impl(cx, hir_ty.hir_id)
-            && let ty = ty_from_hir_ty(cx, hir_ty)
+            // We don't care about infer vars
+            && let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty())
             && (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap))
             && let ty::Adt(_, args) = ty.kind()
             && let ty = args.type_at(1)
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 68e7f807bf5..cd6290ced33 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -399,8 +399,8 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
         TyKind::Tup([head, .., tail]) => (ty_search_pat(head).0, ty_search_pat(tail).1),
         TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")),
         TyKind::Path(qpath) => qpath_search_pat(&qpath),
-        TyKind::Infer => (Pat::Str("_"), Pat::Str("_")),
-        TyKind::TraitObject(_, _, TraitObjectSyntax::Dyn) => (Pat::Str("dyn"), Pat::Str("")),
+        TyKind::Infer(()) => (Pat::Str("_"), Pat::Str("_")),
+        TyKind::TraitObject(_, tagged_ptr) if let TraitObjectSyntax::Dyn = tagged_ptr.tag() => (Pat::Str("dyn"), Pat::Str("")),
         // NOTE: `TraitObject` is incomplete. It will always return true then.
         _ => (Pat::Str(""), Pat::Str("")),
     }
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index a1c48d5c36c..d76231a6eea 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -459,9 +459,9 @@ impl HirEqInterExpr<'_, '_, '_> {
 
     fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
         match (left, right) {
-            (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_const_arg(l, r),
+            (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_const_arg(l.as_unambig_ct(), r.as_unambig_ct()),
             (GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),
-            (GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty),
+            (GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty.as_unambig_ty(), r_ty.as_unambig_ty()),
             (GenericArg::Infer(l_inf), GenericArg::Infer(r_inf)) => self.eq_ty(&l_inf.to_ty(), &r_inf.to_ty()),
             _ => false,
         }
@@ -618,7 +618,7 @@ impl HirEqInterExpr<'_, '_, '_> {
             },
             (TyKind::Path(l), TyKind::Path(r)) => self.eq_qpath(l, r),
             (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
-            (&TyKind::Infer, &TyKind::Infer) => true,
+            (&TyKind::Infer(()), &TyKind::Infer(())) => true,
             _ => false,
         }
     }
@@ -1281,7 +1281,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 }
             },
             TyKind::Path(qpath) => self.hash_qpath(qpath),
-            TyKind::TraitObject(_, lifetime, _) => {
+            TyKind::TraitObject(_, lifetime) => {
                 self.hash_lifetime(lifetime);
             },
             TyKind::Typeof(anon_const) => {
@@ -1291,7 +1291,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 self.hash_ty(binder.inner_ty);
             },
             TyKind::Err(_)
-            | TyKind::Infer
+            | TyKind::Infer(())
             | TyKind::Never
             | TyKind::InferDelegation(..)
             | TyKind::OpaqueDef(_)
@@ -1318,8 +1318,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         for arg in arg_list {
             match *arg {
                 GenericArg::Lifetime(l) => self.hash_lifetime(l),
-                GenericArg::Type(ty) => self.hash_ty(ty),
-                GenericArg::Const(ca) => self.hash_const_arg(ca),
+                GenericArg::Type(ty) => self.hash_ty(ty.as_unambig_ty()),
+                GenericArg::Const(ca) => self.hash_const_arg(ca.as_unambig_ct()),
                 GenericArg::Infer(ref inf) => self.hash_ty(&inf.to_ty()),
             }
         }
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index eecfc3fb13f..93e3fb36b35 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -437,7 +437,7 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tc
         .map_or(&[][..], |a| a.args)
         .iter()
         .filter_map(|a| match a {
-            hir::GenericArg::Type(ty) => Some(*ty),
+            hir::GenericArg::Type(ty) => Some(ty.as_unambig_ty()),
             _ => None,
         })
 }
@@ -2148,7 +2148,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
 pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match expr.kind {
         ExprKind::Closure(&Closure { body, fn_decl, .. })
-            if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer)) =>
+            if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer(()))) =>
         {
             is_body_identity_function(cx, cx.tcx.hir().body(body))
         },
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index d7640ebfb00..b5cec31ba9d 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -14,8 +14,8 @@
 use crate::def_path_res;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{Visitor, walk_qpath, walk_ty};
-use rustc_hir::{self as hir, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind};
+use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_qpath, walk_ty};
+use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty};
 use rustc_span::{Span, Symbol};
@@ -116,14 +116,15 @@ impl<'cx> Visitor<'cx> for CertaintyVisitor<'cx, '_> {
         }
     }
 
-    fn visit_ty(&mut self, ty: &'cx hir::Ty<'_>) {
-        if matches!(ty.kind, TyKind::Infer) {
-            self.certainty = Certainty::Uncertain;
-        }
+    fn visit_ty(&mut self, ty: &'cx hir::Ty<'_, AmbigArg>) {
         if self.certainty != Certainty::Uncertain {
             walk_ty(self, ty);
         }
     }
+
+    fn visit_infer(&mut self, _inf_id: HirId, _inf_span: Span, _kind: InferKind<'cx>) -> Self::Result {
+        self.certainty = Certainty::Uncertain;
+    }
 }
 
 fn type_certainty(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Certainty {
@@ -139,7 +140,7 @@ fn type_certainty(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Certainty {
     }
 
     let mut visitor = CertaintyVisitor::new(cx);
-    visitor.visit_ty(ty);
+    visitor.visit_ty_unambig(ty);
     visitor.certainty
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 7a3a861a9ca..dcc763a8abd 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -2,7 +2,7 @@ use crate::ty::needs_ordered_drop;
 use crate::{get_enclosing_block, path_to_local_id};
 use core::ops::ControlFlow;
 use rustc_ast::visit::{VisitorResult, try_visit};
-use rustc_hir as hir;
+use rustc_hir::{self as hir, AmbigArg};
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::intravisit::{self, Visitor, walk_block, walk_expr};
 use rustc_hir::{
@@ -122,7 +122,7 @@ pub fn for_each_expr_without_closures<'tcx, B, C: Continue>(
         }
 
         // Avoid unnecessary `walk_*` calls.
-        fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> Self::Result {
+        fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
             ControlFlow::Continue(())
         }
         fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> Self::Result {
@@ -172,7 +172,7 @@ pub fn for_each_expr<'tcx, B, C: Continue>(
             ControlFlow::Continue(())
         }
         // Avoid unnecessary `walk_*` calls.
-        fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> Self::Result {
+        fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
             ControlFlow::Continue(())
         }
         fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> Self::Result {
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 75ef60a5dc8..68edefd3095 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -186,7 +186,7 @@ pub fn main() {
 
     rustc_driver::init_rustc_env_logger(&early_dcx);
 
-    let using_internal_features = rustc_driver::install_ice_hook(BUG_REPORT_URL, |dcx| {
+    rustc_driver::install_ice_hook(BUG_REPORT_URL, |dcx| {
         // FIXME: this macro calls unwrap internally but is called in a panicking context!  It's not
         // as simple as moving the call from the hook to main, because `install_ice_hook` doesn't
         // accept a generic closure.
@@ -236,7 +236,7 @@ pub fn main() {
             let mut args: Vec<String> = orig_args.clone();
             pass_sysroot_env_if_given(&mut args, sys_root_env);
 
-            rustc_driver::RunCompiler::new(&args, &mut DefaultCallbacks).run();
+            rustc_driver::run_compiler(&args, &mut DefaultCallbacks);
             return Ok(());
         }
 
@@ -295,13 +295,9 @@ pub fn main() {
         let clippy_enabled = !cap_lints_allow && relevant_package && !info_query;
         if clippy_enabled {
             args.extend(clippy_args);
-            rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var })
-                .set_using_internal_features(using_internal_features)
-                .run();
+            rustc_driver::run_compiler(&args, &mut ClippyCallbacks { clippy_args_var });
         } else {
-            rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var })
-                .set_using_internal_features(using_internal_features)
-                .run();
+            rustc_driver::run_compiler(&args, &mut RustcCallbacks { clippy_args_var });
         }
         Ok(())
     }))
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index c6f3d7c0d10..00821fc9f9d 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -488,6 +488,17 @@ impl Config {
             git_merge_commit_email: &self.git_merge_commit_email,
         }
     }
+
+    pub fn has_subprocess_support(&self) -> bool {
+        // FIXME(#135928): compiletest is always a **host** tool. Building and running an
+        // capability detection executable against the **target** is not trivial. The short term
+        // solution here is to hard-code some targets to allow/deny, unfortunately.
+
+        let unsupported_target = self.target_cfg().env == "sgx"
+            || matches!(self.target_cfg().arch.as_str(), "wasm32" | "wasm64")
+            || self.target_cfg().os == "emscripten";
+        !unsupported_target
+    }
 }
 
 /// Known widths of `target_has_atomic`.
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index 5784cd83119..acdb3cbdd45 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -152,6 +152,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "needs-sanitizer-support",
     "needs-sanitizer-thread",
     "needs-std-debug-assertions",
+    "needs-subprocess",
     "needs-symlink",
     "needs-target-has-atomic",
     "needs-threads",
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index e19dcd992fc..12f0790fb10 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -95,6 +95,11 @@ pub(super) fn handle_needs(
             ignore_reason: "ignored on targets without threading support",
         },
         Need {
+            name: "needs-subprocess",
+            condition: config.has_subprocess_support(),
+            ignore_reason: "ignored on targets without subprocess support",
+        },
+        Need {
             name: "needs-unwind",
             condition: config.can_unwind(),
             ignore_reason: "ignored on targets without unwinding support",
@@ -351,6 +356,9 @@ fn find_dlltool(config: &Config) -> bool {
     dlltool_found
 }
 
+// FIXME(#135928): this is actually not quite right because this detection is run on the **host**.
+// This however still helps the case of windows -> windows local development in case symlinks are
+// not available.
 #[cfg(windows)]
 fn has_symlinks() -> bool {
     if std::env::var_os("CI").is_some() {
diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs
index 7fcb8ffd1f9..a37e6c2eb5c 100644
--- a/src/tools/jsondoclint/src/validator/tests.rs
+++ b/src/tools/jsondoclint/src/validator/tests.rs
@@ -163,7 +163,7 @@ fn errors_on_missing_path() {
                     sig: FunctionSignature {
                         inputs: vec![],
                         output: Some(Type::ResolvedPath(Path {
-                            name: "Bar".to_owned(),
+                            path: "Bar".to_owned(),
                             id: Id(1),
                             args: None,
                         })),
@@ -191,7 +191,7 @@ fn errors_on_missing_path() {
 
     check(&krate, &[Error {
         kind: ErrorKind::Custom(
-            r#"No entry in '$.paths' for Path { name: "Bar", id: Id(1), args: None }"#.to_owned(),
+            r#"No entry in '$.paths' for Path { path: "Bar", id: Id(1), args: None }"#.to_owned(),
         ),
         id: Id(1),
     }]);
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index 570b2c374c0..19340b5d07a 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -50,6 +50,29 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[
     ("alloc/slice/trait.Concat.html", &["#method.concat"]),
     ("alloc/slice/index.html", &["#method.concat", "#method.join"]),
     ("alloc/vec/struct.Vec.html", &["#method.sort_by_key", "#method.sort_by_cached_key"]),
+    ("alloc/bstr/struct.ByteStr.html", &[
+        "#method.to_ascii_uppercase",
+        "#method.to_ascii_lowercase",
+        "core/slice::sort_by_key",
+        "core\\slice::sort_by_key",
+        "#method.sort_by_cached_key",
+        "#method.sort_by_key"
+    ]),
+    ("alloc/bstr/struct.ByteString.html", &[
+        "#method.to_ascii_uppercase",
+        "#method.to_ascii_lowercase",
+        "core/slice::sort_by_key",
+        "core\\slice::sort_by_key",
+        "#method.sort_by_cached_key",
+        "#method.sort_by_key"
+    ]),
+    ("core/bstr/struct.ByteStr.html", &[
+        "#method.to_ascii_uppercase",
+        "#method.to_ascii_lowercase",
+        "core/bstr/slice::sort_by_key",
+        "core\\bstr\\slice::sort_by_key",
+        "#method.sort_by_cached_key"
+    ]),
     ("core/primitive.str.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase"]),
     ("core/primitive.slice.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase",
                                     "core/slice::sort_by_key", "core\\slice::sort_by_key",
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 22c15c8405f..a2e9c63f79e 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -30,7 +30,7 @@ use std::ops::Range;
 use std::path::PathBuf;
 use std::str::FromStr;
 use std::sync::atomic::{AtomicI32, Ordering};
-use std::sync::{Arc, Once};
+use std::sync::Once;
 
 use miri::{
     BacktraceStyle, BorrowTrackerMethod, MiriConfig, MiriEntryFnType,ProvenanceMode, RetagFields, ValidationMode,
@@ -370,13 +370,10 @@ fn init_late_loggers(early_dcx: &EarlyDiagCtxt, tcx: TyCtxt<'_>) {
 fn run_compiler_and_exit(
     args: &[String],
     callbacks: &mut (dyn rustc_driver::Callbacks + Send),
-    using_internal_features: Arc<std::sync::atomic::AtomicBool>,
 ) -> ! {
     // Invoke compiler, and handle return code.
     let exit_code = rustc_driver::catch_with_exit_code(move || {
-        rustc_driver::RunCompiler::new(args, callbacks)
-            .set_using_internal_features(using_internal_features)
-            .run();
+        rustc_driver::run_compiler(args, callbacks);
         Ok(())
     });
     std::process::exit(exit_code)
@@ -467,8 +464,7 @@ fn main() {
     // If the environment asks us to actually be rustc, then do that.
     if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
         // Earliest rustc setup.
-        let using_internal_features =
-            rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ());
+        rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ());
         rustc_driver::init_rustc_env_logger(&early_dcx);
 
         let target_crate = if crate_kind == "target" {
@@ -492,16 +488,11 @@ fn main() {
         }
 
         // We cannot use `rustc_driver::main` as we want it to use `args` as the CLI arguments.
-        run_compiler_and_exit(
-            &args,
-            &mut MiriBeRustCompilerCalls { target_crate },
-            using_internal_features,
-        )
+        run_compiler_and_exit(&args, &mut MiriBeRustCompilerCalls { target_crate })
     }
 
     // Add an ICE bug report hook.
-    let using_internal_features =
-        rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ());
+    rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ());
 
     // Init loggers the Miri way.
     init_early_loggers(&early_dcx);
@@ -735,9 +726,5 @@ fn main() {
 
     debug!("rustc arguments: {:?}", rustc_args);
     debug!("crate arguments: {:?}", miri_config.args);
-    run_compiler_and_exit(
-        &rustc_args,
-        &mut MiriCompilerCalls::new(miri_config, many_seeds),
-        using_internal_features,
-    )
+    run_compiler_and_exit(&rustc_args, &mut MiriCompilerCalls::new(miri_config, many_seeds))
 }
diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs
index 6269d91c7ec..2a4cff1d12e 100644
--- a/src/tools/tidy/src/ext_tool_checks.rs
+++ b/src/tools/tidy/src/ext_tool_checks.rs
@@ -89,74 +89,45 @@ fn check_impl(
 
     if python_lint {
         eprintln!("linting python files");
-        let mut cfg_args_ruff = cfg_args.clone();
-        let mut file_args_ruff = file_args.clone();
-
-        let mut cfg_path = root_path.to_owned();
-        cfg_path.extend(RUFF_CONFIG_PATH);
-        let mut cache_dir = outdir.to_owned();
-        cache_dir.extend(RUFF_CACHE_PATH);
-
-        cfg_args_ruff.extend([
-            "--config".as_ref(),
-            cfg_path.as_os_str(),
-            "--cache-dir".as_ref(),
-            cache_dir.as_os_str(),
-        ]);
-
-        if file_args_ruff.is_empty() {
-            file_args_ruff.push(root_path.as_os_str());
-        }
-
-        let mut args = merge_args(&cfg_args_ruff, &file_args_ruff);
-        args.insert(0, "check".as_ref());
-        let res = py_runner(py_path.as_ref().unwrap(), true, None, "ruff", &args);
+        let py_path = py_path.as_ref().unwrap();
+        let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, &["check".as_ref()]);
 
         if res.is_err() && show_diff {
             eprintln!("\npython linting failed! Printing diff suggestions:");
 
-            args.insert(1, "--diff".as_ref());
-            let _ = py_runner(py_path.as_ref().unwrap(), true, None, "ruff", &args);
+            let _ = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, &[
+                "check".as_ref(),
+                "--diff".as_ref(),
+            ]);
         }
         // Rethrow error
         let _ = res?;
     }
 
     if python_fmt {
-        let mut cfg_args_ruff = cfg_args.clone();
-        let mut file_args_ruff = file_args.clone();
-
+        let mut args: Vec<&OsStr> = vec!["format".as_ref()];
         if bless {
             eprintln!("formatting python files");
         } else {
             eprintln!("checking python file formatting");
-            cfg_args_ruff.push("--check".as_ref());
-        }
-
-        let mut cfg_path = root_path.to_owned();
-        cfg_path.extend(RUFF_CONFIG_PATH);
-        let mut cache_dir = outdir.to_owned();
-        cache_dir.extend(RUFF_CACHE_PATH);
-
-        cfg_args_ruff.extend(["--config".as_ref(), cfg_path.as_os_str()]);
-
-        if file_args_ruff.is_empty() {
-            file_args_ruff.push(root_path.as_os_str());
+            args.push("--check".as_ref());
         }
 
-        let mut args = merge_args(&cfg_args_ruff, &file_args_ruff);
-        args.insert(0, "format".as_ref());
-        let res = py_runner(py_path.as_ref().unwrap(), true, None, "ruff", &args);
+        let py_path = py_path.as_ref().unwrap();
+        let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, &args);
 
-        if res.is_err() && show_diff {
-            eprintln!("\npython formatting does not match! Printing diff:");
-
-            args.insert(0, "--diff".as_ref());
-            let _ = py_runner(py_path.as_ref().unwrap(), true, None, "ruff", &args);
-        }
         if res.is_err() && !bless {
+            if show_diff {
+                eprintln!("\npython formatting does not match! Printing diff:");
+
+                let _ = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, &[
+                    "format".as_ref(),
+                    "--diff".as_ref(),
+                ]);
+            }
             eprintln!("rerun tidy with `--extra-checks=py:fmt --bless` to reformat Python code");
         }
+
         // Rethrow error
         let _ = res?;
     }
@@ -247,6 +218,38 @@ fn check_impl(
     Ok(())
 }
 
+fn run_ruff(
+    root_path: &Path,
+    outdir: &Path,
+    py_path: &Path,
+    cfg_args: &[&OsStr],
+    file_args: &[&OsStr],
+    ruff_args: &[&OsStr],
+) -> Result<(), Error> {
+    let mut cfg_args_ruff = cfg_args.into_iter().copied().collect::<Vec<_>>();
+    let mut file_args_ruff = file_args.into_iter().copied().collect::<Vec<_>>();
+
+    let mut cfg_path = root_path.to_owned();
+    cfg_path.extend(RUFF_CONFIG_PATH);
+    let mut cache_dir = outdir.to_owned();
+    cache_dir.extend(RUFF_CACHE_PATH);
+
+    cfg_args_ruff.extend([
+        "--config".as_ref(),
+        cfg_path.as_os_str(),
+        "--cache-dir".as_ref(),
+        cache_dir.as_os_str(),
+    ]);
+
+    if file_args_ruff.is_empty() {
+        file_args_ruff.push(root_path.as_os_str());
+    }
+
+    let mut args: Vec<&OsStr> = ruff_args.into_iter().copied().collect();
+    args.extend(merge_args(&cfg_args_ruff, &file_args_ruff));
+    py_runner(py_path, true, None, "ruff", &args)
+}
+
 /// Helper to create `cfg1 cfg2 -- file1 file2` output
 fn merge_args<'a>(cfg_args: &[&'a OsStr], file_args: &[&'a OsStr]) -> Vec<&'a OsStr> {
     let mut args = cfg_args.to_owned();
@@ -321,8 +324,16 @@ fn get_or_create_venv(venv_path: &Path, src_reqs_path: &Path) -> Result<PathBuf,
 fn create_venv_at_path(path: &Path) -> Result<(), Error> {
     /// Preferred python versions in order. Newest to oldest then current
     /// development versions
-    const TRY_PY: &[&str] =
-        &["python3.11", "python3.10", "python3.9", "python3", "python", "python3.12", "python3.13"];
+    const TRY_PY: &[&str] = &[
+        "python3.13",
+        "python3.12",
+        "python3.11",
+        "python3.10",
+        "python3.9",
+        "python3",
+        "python",
+        "python3.14",
+    ];
 
     let mut sys_py = None;
     let mut found = Vec::new();
@@ -357,22 +368,40 @@ fn create_venv_at_path(path: &Path) -> Result<(), Error> {
         return Err(ret);
     };
 
-    eprintln!("creating virtual environment at '{}' using '{sys_py}'", path.display());
-    let out = Command::new(sys_py).args(["-m", "virtualenv"]).arg(path).output().unwrap();
+    // First try venv, which should be packaged in the Python3 standard library.
+    // If it is not available, try to create the virtual environment using the
+    // virtualenv package.
+    if try_create_venv(sys_py, path, "venv").is_ok() {
+        return Ok(());
+    }
+    try_create_venv(sys_py, path, "virtualenv")
+}
+
+fn try_create_venv(python: &str, path: &Path, module: &str) -> Result<(), Error> {
+    eprintln!(
+        "creating virtual environment at '{}' using '{python}' and '{module}'",
+        path.display()
+    );
+    let out = Command::new(python).args(["-m", module]).arg(path).output().unwrap();
 
     if out.status.success() {
         return Ok(());
     }
 
     let stderr = String::from_utf8_lossy(&out.stderr);
-    let err = if stderr.contains("No module named virtualenv") {
+    let err = if stderr.contains(&format!("No module named {module}")) {
         Error::Generic(format!(
-            "virtualenv not found: you may need to install it \
-                               (`{sys_py} -m pip install virtualenv`)"
+            r#"{module} not found: you may need to install it:
+`{python} -m pip install {module}`
+If you see an error about "externally managed environment" when running the above command,
+either install `{module}` using your system package manager
+(e.g. `sudo apt-get install {python}-{module}`) or create a virtual environment manually, install
+`{module}` in it and then activate it before running tidy.
+"#
         ))
     } else {
         Error::Generic(format!(
-            "failed to create venv at '{}' using {sys_py}: {stderr}",
+            "failed to create venv at '{}' using {python} -m {module}: {stderr}",
             path.display()
         ))
     };
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index de3380502bf..0e5a7458b68 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -2204,7 +2204,6 @@ ui/issues/issue-3895.rs
 ui/issues/issue-38954.rs
 ui/issues/issue-38987.rs
 ui/issues/issue-39089.rs
-ui/issues/issue-39175.rs
 ui/issues/issue-39211.rs
 ui/issues/issue-39367.rs
 ui/issues/issue-39548.rs
@@ -3857,7 +3856,6 @@ ui/suggestions/issue-106443-sugg-clone-for-arg.rs
 ui/suggestions/issue-106443-sugg-clone-for-bound.rs
 ui/suggestions/issue-107860.rs
 ui/suggestions/issue-108470.rs
-ui/suggestions/issue-109195.rs
 ui/suggestions/issue-109291.rs
 ui/suggestions/issue-109396.rs
 ui/suggestions/issue-109436.rs
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 63ac447a772..5ef07911429 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use ignore::Walk;
 const ENTRY_LIMIT: u32 = 901;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: u32 = 1664;
+const ISSUES_ENTRY_LIMIT: u32 = 1662;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/assembly/powerpc64-struct-abi.rs b/tests/assembly/powerpc64-struct-abi.rs
index 7052937acf6..db08a514819 100644
--- a/tests/assembly/powerpc64-struct-abi.rs
+++ b/tests/assembly/powerpc64-struct-abi.rs
@@ -50,9 +50,9 @@ struct ThreeU8s(u8, u8, u8);
 
 // CHECK-LABEL: read_large
 // aix: lwz [[REG1:.*]], 16(4)
-// aix-NEXT: lxvd2x 0, 0, 4
+// aix-NEXT: lxv{{d2x|w4x}} 0, 0, 4
 // aix-NEXT: stw [[REG1]], 16(3)
-// aix-NEXT: stxvd2x 0, 0, 3
+// aix-NEXT: stxv{{d2x|w4x}} 0, 0, 3
 // be: lwz [[REG1:.*]], 16(4)
 // be-NEXT: stw [[REG1]], 16(3)
 // be-NEXT: ld [[REG2:.*]], 8(4)
@@ -118,8 +118,8 @@ extern "C" fn read_small(x: &ThreeU8s) -> ThreeU8s {
 // aix-NEXT: std 4, 56(1)
 // aix-NEXT: stw [[REG1]], 16(6)
 // aix-NEXT: addi [[REG2:.*]], 1, 48
-// aix-NEXT: lxvd2x 0, 0, [[REG2]]
-// aix-NEXT: stxvd2x 0, 0, 6
+// aix-NEXT: lxv{{d2x|w4x}} 0, 0, [[REG2]]
+// aix-NEXT: stxv{{d2x|w4x}} 0, 0, 6
 // elf: std 3, 0(6)
 // be-NEXT: rldicl [[REG1:.*]], 5, 32, 32
 // elf-NEXT: std 4, 8(6)
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index acfa868c2df..6bb3389c409 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -66,6 +66,9 @@
 //@ revisions: aarch64_unknown_teeos
 //@ [aarch64_unknown_teeos] compile-flags: --target aarch64-unknown-teeos
 //@ [aarch64_unknown_teeos] needs-llvm-components: aarch64
+//@ revisions: aarch64_unknown_nuttx
+//@ [aarch64_unknown_nuttx] compile-flags: --target aarch64-unknown-nuttx
+//@ [aarch64_unknown_nuttx] needs-llvm-components: aarch64
 //@ revisions: aarch64_unknown_trusty
 //@ [aarch64_unknown_trusty] compile-flags: --target aarch64-unknown-trusty
 //@ [aarch64_unknown_trusty] needs-llvm-components: aarch64
@@ -177,6 +180,12 @@
 //@ revisions: armv7a_none_eabihf
 //@ [armv7a_none_eabihf] compile-flags: --target armv7a-none-eabihf
 //@ [armv7a_none_eabihf] needs-llvm-components: arm
+//@ revisions: armv7a_nuttx_eabi
+//@ [armv7a_nuttx_eabi] compile-flags: --target armv7a-nuttx-eabi
+//@ [armv7a_nuttx_eabi] needs-llvm-components: arm
+//@ revisions: armv7a_nuttx_eabihf
+//@ [armv7a_nuttx_eabihf] compile-flags: --target armv7a-nuttx-eabihf
+//@ [armv7a_nuttx_eabihf] needs-llvm-components: arm
 //@ revisions: armv7r_none_eabi
 //@ [armv7r_none_eabi] compile-flags: --target armv7r-none-eabi
 //@ [armv7r_none_eabi] needs-llvm-components: arm
@@ -621,6 +630,12 @@
 //@ revisions: thumbv6m_nuttx_eabi
 //@ [thumbv6m_nuttx_eabi] compile-flags: --target thumbv6m-nuttx-eabi
 //@ [thumbv6m_nuttx_eabi] needs-llvm-components: arm
+//@ revisions: thumbv7a_nuttx_eabi
+//@ [thumbv7a_nuttx_eabi] compile-flags: --target thumbv7a-nuttx-eabi
+//@ [thumbv7a_nuttx_eabi] needs-llvm-components: arm
+//@ revisions: thumbv7a_nuttx_eabihf
+//@ [thumbv7a_nuttx_eabihf] compile-flags: --target thumbv7a-nuttx-eabihf
+//@ [thumbv7a_nuttx_eabihf] needs-llvm-components: arm
 //@ revisions: thumbv7m_nuttx_eabi
 //@ [thumbv7m_nuttx_eabi] compile-flags: --target thumbv7m-nuttx-eabi
 //@ [thumbv7m_nuttx_eabi] needs-llvm-components: arm
diff --git a/tests/assembly/wasm32-naked-fn.rs b/tests/assembly/wasm32-naked-fn.rs
new file mode 100644
index 00000000000..4911a6bd08f
--- /dev/null
+++ b/tests/assembly/wasm32-naked-fn.rs
@@ -0,0 +1,199 @@
+// FIXME: add wasm32-unknown when the wasm32-unknown-unknown ABI is fixed
+// see https://github.com/rust-lang/rust/issues/115666
+//@ revisions: wasm64-unknown wasm32-wasip1
+//@ add-core-stubs
+//@ assembly-output: emit-asm
+//@ [wasm64-unknown] compile-flags: --target wasm64-unknown-unknown
+//@ [wasm32-wasip1] compile-flags: --target wasm32-wasip1
+//@ [wasm64-unknown] needs-llvm-components: webassembly
+//@ [wasm32-wasip1] needs-llvm-components: webassembly
+
+#![crate_type = "lib"]
+#![feature(no_core, naked_functions, asm_experimental_arch, f128, linkage, fn_align)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK: .section  .text.nop,"",@
+// CHECK: .globl nop
+// CHECK-LABEL: nop:
+// CHECK: .functype nop () -> ()
+// CHECK-NOT: .size
+// CHECK: end_function
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn nop() {
+    naked_asm!("nop")
+}
+
+// CHECK: .section  .text.weak_aligned_nop,"",@
+// CHECK: .weak weak_aligned_nop
+// CHECK-LABEL: nop:
+// CHECK: .functype weak_aligned_nop () -> ()
+// CHECK-NOT: .size
+// CHECK: end_function
+#[no_mangle]
+#[naked]
+#[linkage = "weak"]
+// wasm functions cannot be aligned, so this has no effect
+#[repr(align(32))]
+unsafe extern "C" fn weak_aligned_nop() {
+    naked_asm!("nop")
+}
+
+// CHECK-LABEL: fn_i8_i8:
+// CHECK-NEXT: .functype fn_i8_i8 (i32) -> (i32)
+//
+// CHECK-NEXT: local.get 0
+// CHECK-NEXT: local.get 0
+// CHECK-NEXT: i32.mul
+//
+// CHECK-NEXT: end_function
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn fn_i8_i8(num: i8) -> i8 {
+    naked_asm!("local.get 0", "local.get 0", "i32.mul")
+}
+
+// CHECK-LABEL: fn_i8_i8_i8:
+// CHECK: .functype fn_i8_i8_i8 (i32, i32) -> (i32)
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 {
+    naked_asm!("local.get 1", "local.get 0", "i32.mul")
+}
+
+// CHECK-LABEL: fn_unit_i8:
+// CHECK: .functype fn_unit_i8 () -> (i32)
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn fn_unit_i8() -> i8 {
+    naked_asm!("i32.const 42")
+}
+
+// CHECK-LABEL: fn_i8_unit:
+// CHECK: .functype fn_i8_unit (i32) -> ()
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn fn_i8_unit(_: i8) {
+    naked_asm!("nop")
+}
+
+// CHECK-LABEL: fn_i32_i32:
+// CHECK: .functype fn_i32_i32 (i32) -> (i32)
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn fn_i32_i32(num: i32) -> i32 {
+    naked_asm!("local.get 0", "local.get 0", "i32.mul")
+}
+
+// CHECK-LABEL: fn_i64_i64:
+// CHECK: .functype fn_i64_i64 (i64) -> (i64)
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn fn_i64_i64(num: i64) -> i64 {
+    naked_asm!("local.get 0", "local.get 0", "i64.mul")
+}
+
+// CHECK-LABEL: fn_i128_i128:
+// wasm32-wasip1: .functype fn_i128_i128 (i32, i64, i64) -> ()
+// wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> ()
+#[allow(improper_ctypes_definitions)]
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn fn_i128_i128(num: i128) -> i128 {
+    naked_asm!(
+        "local.get       0",
+        "local.get       2",
+        "i64.store       8",
+        "local.get       0",
+        "local.get       1",
+        "i64.store       0",
+    )
+}
+
+// CHECK-LABEL: fn_f128_f128:
+// wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> ()
+// wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> ()
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn fn_f128_f128(num: f128) -> f128 {
+    naked_asm!(
+        "local.get       0",
+        "local.get       2",
+        "i64.store       8",
+        "local.get       0",
+        "local.get       1",
+        "i64.store       0",
+    )
+}
+
+#[repr(C)]
+struct Compound {
+    a: u16,
+    b: i64,
+}
+
+// CHECK-LABEL: fn_compound_compound:
+// wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> ()
+// wasm64-unknown: .functype fn_compound_compound (i64, i64) -> ()
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn fn_compound_compound(_: Compound) -> Compound {
+    // this is the wasm32-wasip1 assembly
+    naked_asm!(
+        "local.get       0",
+        "local.get       1",
+        "i64.load        8",
+        "i64.store       8",
+        "local.get       0",
+        "local.get       1",
+        "i32.load16_u    0",
+        "i32.store16     0",
+    )
+}
+
+#[repr(C)]
+struct WrapperI32(i32);
+
+// CHECK-LABEL: fn_wrapperi32_wrapperi32:
+// CHECK: .functype fn_wrapperi32_wrapperi32 (i32) -> (i32)
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 {
+    naked_asm!("local.get       0")
+}
+
+#[repr(C)]
+struct WrapperI64(i64);
+
+// CHECK-LABEL: fn_wrapperi64_wrapperi64:
+// CHECK: .functype fn_wrapperi64_wrapperi64 (i64) -> (i64)
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 {
+    naked_asm!("local.get       0")
+}
+
+#[repr(C)]
+struct WrapperF32(f32);
+
+// CHECK-LABEL: fn_wrapperf32_wrapperf32:
+// CHECK: .functype fn_wrapperf32_wrapperf32 (f32) -> (f32)
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 {
+    naked_asm!("local.get       0")
+}
+
+#[repr(C)]
+struct WrapperF64(f64);
+
+// CHECK-LABEL: fn_wrapperf64_wrapperf64:
+// CHECK: .functype fn_wrapperf64_wrapperf64 (f64) -> (f64)
+#[no_mangle]
+#[naked]
+unsafe extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 {
+    naked_asm!("local.get       0")
+}
diff --git a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
index 148ff86354b..a91d88984a8 100644
--- a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
@@ -4,8 +4,8 @@
   fn bar() -> bool {
       let mut _0: bool;
   
-+     coverage body span: $DIR/instrument_coverage.rs:19:18: 21:2 (#0)
-+     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:19:1: 21:2 (#0);
++     coverage body span: $DIR/instrument_coverage.rs:29:18: 31:2 (#0)
++     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:29:1: 31:2 (#0);
 + 
       bb0: {
 +         Coverage::CounterIncrement(0);
diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
index fa09cf0b83f..d7ea442518e 100644
--- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
@@ -7,13 +7,13 @@
       let mut _2: bool;
       let mut _3: !;
   
-+     coverage body span: $DIR/instrument_coverage.rs:10:11: 16:2 (#0)
++     coverage body span: $DIR/instrument_coverage.rs:14:11: 20:2 (#0)
 +     coverage ExpressionId(0) => Expression { lhs: Counter(1), op: Subtract, rhs: Counter(0) };
-+     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:10:1: 10:11 (#0);
-+     coverage Code(Counter(1)) => $DIR/instrument_coverage.rs:12:12: 12:17 (#0);
-+     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:13:13: 13:18 (#0);
-+     coverage Code(Expression(0)) => $DIR/instrument_coverage.rs:14:10: 14:10 (#0);
-+     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:16:2: 16:2 (#0);
++     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:14:1: 14:11 (#0);
++     coverage Code(Counter(1)) => $DIR/instrument_coverage.rs:16:12: 16:17 (#0);
++     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:17:13: 17:18 (#0);
++     coverage Code(Expression(0)) => $DIR/instrument_coverage.rs:18:10: 18:10 (#0);
++     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:20:2: 20:2 (#0);
 + 
       bb0: {
 +         Coverage::CounterIncrement(0);
diff --git a/tests/mir-opt/coverage/instrument_coverage.rs b/tests/mir-opt/coverage/instrument_coverage.rs
index beb88b607f9..c49786f9615 100644
--- a/tests/mir-opt/coverage/instrument_coverage.rs
+++ b/tests/mir-opt/coverage/instrument_coverage.rs
@@ -6,7 +6,11 @@
 //@ compile-flags: -Cinstrument-coverage -Zno-profiler-runtime
 
 // EMIT_MIR instrument_coverage.main.InstrumentCoverage.diff
-// EMIT_MIR instrument_coverage.bar.InstrumentCoverage.diff
+// CHECK-LABEL: fn main()
+// CHECK: coverage body span:
+// CHECK: coverage Code(Counter({{[0-9]+}})) =>
+// CHECK: bb0:
+// CHECK: Coverage::CounterIncrement
 fn main() {
     loop {
         if bar() {
@@ -15,14 +19,13 @@ fn main() {
     }
 }
 
+// EMIT_MIR instrument_coverage.bar.InstrumentCoverage.diff
+// CHECK-LABEL: fn bar()
+// CHECK: coverage body span:
+// CHECK: coverage Code(Counter({{[0-9]+}})) =>
+// CHECK: bb0:
+// CHECK: Coverage::CounterIncrement
 #[inline(never)]
 fn bar() -> bool {
     true
 }
-
-// CHECK:     coverage ExpressionId({{[0-9]+}}) =>
-// CHECK-DAG: coverage Code(Counter({{[0-9]+}})) =>
-// CHECK-DAG: coverage Code(Expression({{[0-9]+}})) =>
-// CHECK:     bb0:
-// CHECK-DAG: Coverage::ExpressionUsed({{[0-9]+}})
-// CHECK-DAG: Coverage::CounterIncrement({{[0-9]+}})
diff --git a/tests/rustdoc-json/auxiliary/defines_and_reexports.rs b/tests/rustdoc-json/auxiliary/defines_and_reexports.rs
new file mode 100644
index 00000000000..72434ef152f
--- /dev/null
+++ b/tests/rustdoc-json/auxiliary/defines_and_reexports.rs
@@ -0,0 +1,10 @@
+pub mod m1 {
+    pub struct InPubMod;
+}
+
+mod m2 {
+    pub struct InPrivMod;
+}
+
+pub use m1::{InPubMod, InPubMod as InPubMod2};
+pub use m2::{InPrivMod, InPrivMod as InPrivMod2};
diff --git a/tests/rustdoc-json/blanket_impls.rs b/tests/rustdoc-json/blanket_impls.rs
index f2acabbe372..bf0983e66a1 100644
--- a/tests/rustdoc-json/blanket_impls.rs
+++ b/tests/rustdoc-json/blanket_impls.rs
@@ -4,5 +4,5 @@
 
 //@ has "$.index[*][?(@.name=='Error')].inner.assoc_type"
 //@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.type.resolved_path"
-//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.type.resolved_path.name" \"Infallible\"
+//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.type.resolved_path.path" \"Infallible\"
 pub struct ForBlanketTryFromImpl;
diff --git a/tests/rustdoc-json/fns/async_return.rs b/tests/rustdoc-json/fns/async_return.rs
index 18a8a586e76..ff88fa99c61 100644
--- a/tests/rustdoc-json/fns/async_return.rs
+++ b/tests/rustdoc-json/fns/async_return.rs
@@ -17,7 +17,7 @@ pub async fn get_int_async() -> i32 {
     42
 }
 
-//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.name" '"Future"'
+//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.path" '"Future"'
 //@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name" '"Output"'
 //@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive"  \"i32\"
 //@ is "$.index[*][?(@.name=='get_int_future')].inner.function.header.is_async" false
@@ -25,7 +25,7 @@ pub fn get_int_future() -> impl Future<Output = i32> {
     async { 42 }
 }
 
-//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.name" '"Future"'
+//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.path" '"Future"'
 //@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name" '"Output"'
 //@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive" \"i32\"
 //@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.header.is_async" true
diff --git a/tests/rustdoc-json/impl-trait-in-assoc-type.rs b/tests/rustdoc-json/impl-trait-in-assoc-type.rs
index 907a0f6c603..14ea2950769 100644
--- a/tests/rustdoc-json/impl-trait-in-assoc-type.rs
+++ b/tests/rustdoc-json/impl-trait-in-assoc-type.rs
@@ -10,7 +10,7 @@ impl IntoIterator for AlwaysTrue {
     type Item = bool;
 
     //@ count '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[*]' 1
-    //@ is    '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.name' '"Iterator"'
+    //@ is    '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.path' '"Iterator"'
     //@ count '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[*]' 1
     //@ is    '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name' '"Item"'
     //@ is    '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive' '"bool"'
diff --git a/tests/rustdoc-json/path_name.rs b/tests/rustdoc-json/path_name.rs
new file mode 100644
index 00000000000..67843dfc8ff
--- /dev/null
+++ b/tests/rustdoc-json/path_name.rs
@@ -0,0 +1,83 @@
+// Test for the Path::name field within a single crate.
+//
+// See https://github.com/rust-lang/rust/issues/135600
+// and https://github.com/rust-lang/rust/pull/134880#issuecomment-2596386111
+//
+// ignore-tidy-linelength
+//@ aux-build: defines_and_reexports.rs
+extern crate defines_and_reexports;
+
+mod priv_mod {
+    pub struct InPrivMod;
+}
+
+pub mod pub_mod {
+    pub struct InPubMod;
+}
+
+use priv_mod::InPrivMod as InPrivMod3;
+pub use priv_mod::{InPrivMod, InPrivMod as InPrivMod2};
+use pub_mod::InPubMod as InPubMod3;
+pub use pub_mod::{InPubMod, InPubMod as InPubMod2};
+
+//@ is "$.index[*][?(@.name=='T0')].inner.type_alias.type.resolved_path.path" '"priv_mod::InPrivMod"'
+pub type T0 = priv_mod::InPrivMod;
+//@ is "$.index[*][?(@.name=='T1')].inner.type_alias.type.resolved_path.path" '"InPrivMod"'
+pub type T1 = InPrivMod;
+//@ is "$.index[*][?(@.name=='T2')].inner.type_alias.type.resolved_path.path" '"InPrivMod2"'
+pub type T2 = InPrivMod2;
+//@ is "$.index[*][?(@.name=='T3')].inner.type_alias.type.resolved_path.path" '"priv_mod::InPrivMod"'
+pub type T3 = InPrivMod3;
+
+//@ is "$.index[*][?(@.name=='U0')].inner.type_alias.type.resolved_path.path" '"pub_mod::InPubMod"'
+pub type U0 = pub_mod::InPubMod;
+//@ is "$.index[*][?(@.name=='U1')].inner.type_alias.type.resolved_path.path" '"InPubMod"'
+pub type U1 = InPubMod;
+//@ is "$.index[*][?(@.name=='U2')].inner.type_alias.type.resolved_path.path" '"InPubMod2"'
+pub type U2 = InPubMod2;
+//@ is "$.index[*][?(@.name=='U3')].inner.type_alias.type.resolved_path.path" '"pub_mod::InPubMod"'
+pub type U3 = InPubMod3;
+
+// Check we only have paths for structs at their original path
+//@ ismany "$.paths[*][?(@.crate_id==0 && @.kind=='struct')].path" '["path_name", "priv_mod", "InPrivMod"]' '["path_name", "pub_mod", "InPubMod"]'
+
+pub use defines_and_reexports::{InPrivMod as XPrivMod, InPubMod as XPubMod};
+use defines_and_reexports::{InPrivMod as XPrivMod2, InPubMod as XPubMod2};
+
+//@ is "$.index[*][?(@.name=='X0')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::m1::InPubMod"'
+pub type X0 = defines_and_reexports::m1::InPubMod;
+//@ is "$.index[*][?(@.name=='X1')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPubMod"'
+pub type X1 = defines_and_reexports::InPubMod;
+//@ is "$.index[*][?(@.name=='X2')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPubMod2"'
+pub type X2 = defines_and_reexports::InPubMod2;
+//@ is "$.index[*][?(@.name=='X3')].inner.type_alias.type.resolved_path.path" '"XPubMod"'
+pub type X3 = XPubMod;
+// N.B. This isn't the path as used *or* the original path!
+//@ is "$.index[*][?(@.name=='X4')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPubMod"'
+pub type X4 = XPubMod2;
+
+//@ is "$.index[*][?(@.name=='Y1')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPrivMod"'
+pub type Y1 = defines_and_reexports::InPrivMod;
+//@ is "$.index[*][?(@.name=='Y2')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPrivMod2"'
+pub type Y2 = defines_and_reexports::InPrivMod2;
+//@ is "$.index[*][?(@.name=='Y3')].inner.type_alias.type.resolved_path.path" '"XPrivMod"'
+pub type Y3 = XPrivMod;
+//@ is "$.index[*][?(@.name=='Y4')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPrivMod"'
+pub type Y4 = XPrivMod2;
+
+// For foreign items, $.paths contains the *origional* path, even if it's not publicly
+// assessable. This should probably be changed.
+
+//@ has "$.paths[*].path" '["defines_and_reexports", "m1", "InPubMod"]'
+//@ has "$.paths[*].path" '["defines_and_reexports", "m2", "InPrivMod"]'
+//@ !has "$.paths[*].path" '["defines_and_reexports", "InPubMod"]'
+//@ !has "$.paths[*].path" '["defines_and_reexports", "InPrivMod"]'
+
+// Tests for the example in the docs of Path::name.
+// If these change, chage the docs.
+//@ is "$.index[*][?(@.name=='Vec1')].inner.type_alias.type.resolved_path.path" '"std::vec::Vec"'
+pub type Vec1 = std::vec::Vec<i32>;
+//@ is "$.index[*][?(@.name=='Vec2')].inner.type_alias.type.resolved_path.path" '"Vec"'
+pub type Vec2 = Vec<i32>;
+//@ is "$.index[*][?(@.name=='Vec3')].inner.type_alias.type.resolved_path.path" '"std::prelude::v1::Vec"'
+pub type Vec3 = std::prelude::v1::Vec<i32>;
diff --git a/tests/rustdoc-json/return_private.rs b/tests/rustdoc-json/return_private.rs
index c238a536e0d..bfcbed89040 100644
--- a/tests/rustdoc-json/return_private.rs
+++ b/tests/rustdoc-json/return_private.rs
@@ -2,11 +2,13 @@
 // ignore-tidy-linelength
 
 mod secret {
+    //@ set struct_secret = "$.index[*][?(@.name == 'Secret' && @.inner.struct)].id"
     pub struct Secret;
 }
 
 //@ has "$.index[*][?(@.name=='get_secret')].inner.function"
-//@ is "$.index[*][?(@.name=='get_secret')].inner.function.sig.output.resolved_path.name" \"Secret\"
+//@ is "$.index[*][?(@.name=='get_secret')].inner.function.sig.output.resolved_path.path" '"secret::Secret"'
+//@ is "$.index[*][?(@.name=='get_secret')].inner.function.sig.output.resolved_path.id" $struct_secret
 pub fn get_secret() -> secret::Secret {
     secret::Secret
 }
diff --git a/tests/rustdoc-json/type/dyn.rs b/tests/rustdoc-json/type/dyn.rs
index 97c8689a7c8..f990a2cb53a 100644
--- a/tests/rustdoc-json/type/dyn.rs
+++ b/tests/rustdoc-json/type/dyn.rs
@@ -10,7 +10,7 @@ use std::fmt::Debug;
 //@ has    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias"
 //@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.generics" '{"params": [], "where_predicates": []}'
 //@ has    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path"
-//@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.name" \"Box\"
+//@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.path" \"Box\"
 //@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.constraints" []
 //@ count "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args" 1
 //@ has    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait"
@@ -19,9 +19,9 @@ use std::fmt::Debug;
 //@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].generic_params" []
 //@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].generic_params" []
 //@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].generic_params" []
-//@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.name" '"Fn"'
-//@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.name" '"Send"'
-//@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].trait.name" '"Sync"'
+//@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.path" '"Fn"'
+//@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.path" '"Send"'
+//@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].trait.path" '"Sync"'
 //@ is    "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.args" '{"parenthesized": {"inputs": [],"output": {"primitive": "i32"}}}'
 pub type SyncIntGen = Box<dyn Fn() -> i32 + Send + Sync + 'static>;
 
@@ -34,13 +34,13 @@ pub type SyncIntGen = Box<dyn Fn() -> i32 + Send + Sync + 'static>;
 //@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.lifetime" null
 //@ count "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[*]" 1
 //@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
-//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.name" '"Fn"'
+//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.path" '"Fn"'
 //@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref"
 //@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref.lifetime" "\"'b\""
 //@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref"
 //@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref.lifetime" "\"'b\""
 pub type RefFn<'a> = &'a dyn for<'b> Fn(&'b i32) -> &'b i32;
 
-//@ is    "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.name" '"Send"'
-//@ is    "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.name" '"Debug"'
+//@ is    "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.path" '"Send"'
+//@ is    "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.path" '"Debug"'
 pub type WeirdOrder = Box<dyn Send + Debug>;
diff --git a/tests/rustdoc-json/type/generic_default.rs b/tests/rustdoc-json/type/generic_default.rs
index c1a05805014..7eaa299af5c 100644
--- a/tests/rustdoc-json/type/generic_default.rs
+++ b/tests/rustdoc-json/type/generic_default.rs
@@ -21,10 +21,10 @@ pub struct MyError {}
 //@ is    "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type.default" null
 //@ has    "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path"
 //@ is    "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.id" $my_error
-//@ is    "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.name" \"MyError\"
+//@ is    "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.path" \"MyError\"
 //@ has    "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path"
 //@ is    "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.id" $result
-//@ is    "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.name" \"Result\"
+//@ is    "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.path" \"Result\"
 //@ is    "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.constraints" []
 //@ has    "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.generic"
 //@ has    "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[1].type.generic"
diff --git a/tests/rustdoc-json/type/hrtb.rs b/tests/rustdoc-json/type/hrtb.rs
index 825720e9198..e71d9fc1e1e 100644
--- a/tests/rustdoc-json/type/hrtb.rs
+++ b/tests/rustdoc-json/type/hrtb.rs
@@ -15,7 +15,7 @@ where
 //@ is "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.lifetime" null
 //@ count "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[*]" 1
 //@ is "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
-//@ is "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].trait.name" '"Fn"'
+//@ is "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].trait.path" '"Fn"'
 pub fn dynfn(f: &dyn for<'a, 'b> Fn(&'a i32, &'b i32)) {
     let zero = 0;
     f(&zero, &zero);
diff --git a/tests/ui-fulldeps/compiler-calls.rs b/tests/ui-fulldeps/compiler-calls.rs
index 5fb47c87e50..d6148dfec43 100644
--- a/tests/ui-fulldeps/compiler-calls.rs
+++ b/tests/ui-fulldeps/compiler-calls.rs
@@ -25,7 +25,7 @@ fn main() {
     let mut count = 1;
     let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
     rustc_driver::catch_fatal_errors(|| -> interface::Result<()> {
-        rustc_driver::RunCompiler::new(&args, &mut TestCalls { count: &mut count }).run();
+        rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count });
         Ok(())
     })
     .ok();
diff --git a/tests/ui-fulldeps/obtain-borrowck.rs b/tests/ui-fulldeps/obtain-borrowck.rs
index 8ea2ac61971..f8064c245a8 100644
--- a/tests/ui-fulldeps/obtain-borrowck.rs
+++ b/tests/ui-fulldeps/obtain-borrowck.rs
@@ -47,7 +47,7 @@ fn main() {
         rustc_args.push("-Zpolonius".to_owned());
         let mut callbacks = CompilerCalls::default();
         // Call the Rust compiler with our callbacks.
-        rustc_driver::RunCompiler::new(&rustc_args, &mut callbacks).run();
+        rustc_driver::run_compiler(&rustc_args, &mut callbacks);
         Ok(())
     });
     std::process::exit(exit_code);
diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs
index bcc235e58ed..f414c961627 100644
--- a/tests/ui-fulldeps/run-compiler-twice.rs
+++ b/tests/ui-fulldeps/run-compiler-twice.rs
@@ -72,7 +72,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path
         override_queries: None,
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
-        using_internal_features: std::sync::Arc::default(),
+        using_internal_features: &rustc_driver::USING_INTERNAL_FEATURES,
         expanded_args: Default::default(),
     };
 
diff --git a/tests/ui/abi/homogenous-floats-target-feature-mixup.rs b/tests/ui/abi/homogenous-floats-target-feature-mixup.rs
index 4afb710b193..22b9b029a40 100644
--- a/tests/ui/abi/homogenous-floats-target-feature-mixup.rs
+++ b/tests/ui/abi/homogenous-floats-target-feature-mixup.rs
@@ -5,8 +5,7 @@
 // without #[repr(simd)]
 
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 #![feature(avx512_target_feature)]
 
diff --git a/tests/ui/abi/segfault-no-out-of-stack.rs b/tests/ui/abi/segfault-no-out-of-stack.rs
index 113c82c30e9..b5af13ebfb5 100644
--- a/tests/ui/abi/segfault-no-out-of-stack.rs
+++ b/tests/ui/abi/segfault-no-out-of-stack.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 can't run commands
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-fuchsia must translate zircon signal to SIGSEGV/SIGBUS, FIXME (#58590)
 
 #![feature(rustc_private)]
diff --git a/tests/ui/abi/stack-probes-lto.rs b/tests/ui/abi/stack-probes-lto.rs
index e6c26c5c4de..c6e5bea5f42 100644
--- a/tests/ui/abi/stack-probes-lto.rs
+++ b/tests/ui/abi/stack-probes-lto.rs
@@ -3,7 +3,7 @@
 //@[aarch64] only-aarch64
 //@[x32] only-x86
 //@[x64] only-x86_64
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-musl FIXME #31506
 //@ ignore-fuchsia no exception handler registered for segfault
 //@ compile-flags: -C lto
diff --git a/tests/ui/abi/stack-probes.rs b/tests/ui/abi/stack-probes.rs
index 1c0e50250d7..f0fbd80d2e7 100644
--- a/tests/ui/abi/stack-probes.rs
+++ b/tests/ui/abi/stack-probes.rs
@@ -3,8 +3,7 @@
 //@[aarch64] only-aarch64
 //@[x32] only-x86
 //@[x64] only-x86_64
-//@ ignore-emscripten no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-fuchsia no exception handler registered for segfault
 //@ ignore-nto Crash analysis impossible at SIGSEGV in QNX Neutrino
 //@ ignore-ios Stack probes are enabled, but the SIGSEGV handler isn't
diff --git a/tests/ui/alloc-error/default-alloc-error-hook.rs b/tests/ui/alloc-error/default-alloc-error-hook.rs
index 5f977460b8c..7fbc66ca5f4 100644
--- a/tests/ui/alloc-error/default-alloc-error-hook.rs
+++ b/tests/ui/alloc-error/default-alloc-error-hook.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::alloc::{Layout, handle_alloc_error};
 use std::env;
diff --git a/tests/ui/array-slice-vec/bounds-check-no-overflow.rs b/tests/ui/array-slice-vec/bounds-check-no-overflow.rs
index 4614df44084..c5ff805a853 100644
--- a/tests/ui/array-slice-vec/bounds-check-no-overflow.rs
+++ b/tests/ui/array-slice-vec/bounds-check-no-overflow.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:index out of bounds
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 use std::mem::size_of;
 
diff --git a/tests/ui/array-slice-vec/box-of-array-of-drop-1.rs b/tests/ui/array-slice-vec/box-of-array-of-drop-1.rs
index d64df4f7e4d..c7c05946c4c 100644
--- a/tests/ui/array-slice-vec/box-of-array-of-drop-1.rs
+++ b/tests/ui/array-slice-vec/box-of-array-of-drop-1.rs
@@ -1,12 +1,12 @@
 //@ run-pass
 //@ needs-unwind
+//@ needs-threads
+
 #![allow(overflowing_literals)]
 
 // Test that we cleanup a fixed size Box<[D; k]> properly when D has a
 // destructor.
 
-//@ ignore-emscripten no threads support
-
 use std::thread;
 use std::sync::atomic::{AtomicUsize, Ordering};
 
diff --git a/tests/ui/array-slice-vec/box-of-array-of-drop-2.rs b/tests/ui/array-slice-vec/box-of-array-of-drop-2.rs
index 5ca3d60ad1d..98175a26ec0 100644
--- a/tests/ui/array-slice-vec/box-of-array-of-drop-2.rs
+++ b/tests/ui/array-slice-vec/box-of-array-of-drop-2.rs
@@ -1,12 +1,12 @@
 //@ run-pass
 //@ needs-unwind
+//@ needs-threads
+
 #![allow(overflowing_literals)]
 
 // Test that we cleanup dynamic sized Box<[D]> properly when D has a
 // destructor.
 
-//@ ignore-emscripten no threads support
-
 use std::thread;
 use std::sync::atomic::{AtomicUsize, Ordering};
 
diff --git a/tests/ui/array-slice-vec/dst-raw-slice.rs b/tests/ui/array-slice-vec/dst-raw-slice.rs
index f1281f4e302..ab9dedc139d 100644
--- a/tests/ui/array-slice-vec/dst-raw-slice.rs
+++ b/tests/ui/array-slice-vec/dst-raw-slice.rs
@@ -2,7 +2,7 @@
 
 //@ run-fail
 //@ error-pattern:index out of bounds
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #[allow(unconditional_panic)]
 fn main() {
diff --git a/tests/ui/array-slice-vec/nested-vec-3.rs b/tests/ui/array-slice-vec/nested-vec-3.rs
index ce61401aab4..51975743742 100644
--- a/tests/ui/array-slice-vec/nested-vec-3.rs
+++ b/tests/ui/array-slice-vec/nested-vec-3.rs
@@ -1,8 +1,8 @@
 //@ run-pass
 //@ needs-unwind
-#![allow(overflowing_literals)]
+//@ needs-threads
 
-//@ ignore-emscripten no threads support
+#![allow(overflowing_literals)]
 
 // Test that using the `vec!` macro nested within itself works when
 // the contents implement Drop and we hit a panic in the middle of
diff --git a/tests/ui/array-slice-vec/slice-panic-1.rs b/tests/ui/array-slice-vec/slice-panic-1.rs
index d4f584c1632..a745dff96af 100644
--- a/tests/ui/array-slice-vec/slice-panic-1.rs
+++ b/tests/ui/array-slice-vec/slice-panic-1.rs
@@ -1,7 +1,6 @@
 //@ run-pass
 //@ needs-unwind
-
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 // Test that if a slicing expr[..] fails, the correct cleanups happen.
 
diff --git a/tests/ui/array-slice-vec/slice-panic-2.rs b/tests/ui/array-slice-vec/slice-panic-2.rs
index b3d1dc45573..483a4cbe245 100644
--- a/tests/ui/array-slice-vec/slice-panic-2.rs
+++ b/tests/ui/array-slice-vec/slice-panic-2.rs
@@ -1,7 +1,6 @@
 //@ run-pass
 //@ needs-unwind
-
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 // Test that if a slicing expr[..] fails, the correct cleanups happen.
 
diff --git a/tests/ui/array-slice-vec/vec-overrun.rs b/tests/ui/array-slice-vec/vec-overrun.rs
index 10f8350869f..3b3e9215279 100644
--- a/tests/ui/array-slice-vec/vec-overrun.rs
+++ b/tests/ui/array-slice-vec/vec-overrun.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:index out of bounds: the len is 1 but the index is 2
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     let v: Vec<isize> = vec![10];
diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
index c5260adbed4..88db3611719 100644
--- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
+++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
@@ -40,14 +40,14 @@ LL | type X = std::ops::Deref::Target;
    |
 help: use fully-qualified syntax
    |
+LL | type X = <ByteStr as Deref>::Target;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | type X = <ByteString as Deref>::Target;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL | type X = <CString as Deref>::Target;
    |          ~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL | type X = <IoSlice<'_> as Deref>::Target;
    |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL | type X = <IoSliceMut<'_> as Deref>::Target;
-   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL | type X = <OsString as Deref>::Target;
-   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~
      and N other candidates
 
 error: aborting due to 5 previous errors
diff --git a/tests/ui/async-await/coroutine-desc.stderr b/tests/ui/async-await/coroutine-desc.stderr
index 01482a9cb1f..84a1a3166ad 100644
--- a/tests/ui/async-await/coroutine-desc.stderr
+++ b/tests/ui/async-await/coroutine-desc.stderr
@@ -30,7 +30,6 @@ LL |     fun(one(), two());
    |     |   expected all arguments to be this future type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
-   = help: consider `await`ing on both `Future`s
    = note: distinct uses of `impl Trait` result in different opaque types
 note: function defined here
   --> $DIR/coroutine-desc.rs:7:4
diff --git a/tests/ui/async-await/dont-suggest-missing-await.stderr b/tests/ui/async-await/dont-suggest-missing-await.stderr
index 45a226c31f8..2ca52b2d5f5 100644
--- a/tests/ui/async-await/dont-suggest-missing-await.stderr
+++ b/tests/ui/async-await/dont-suggest-missing-await.stderr
@@ -6,20 +6,11 @@ LL |         take_u32(x)
    |         |
    |         arguments to this function are incorrect
    |
-note: calling an async function returns a future
-  --> $DIR/dont-suggest-missing-await.rs:14:18
-   |
-LL |         take_u32(x)
-   |                  ^
 note: function defined here
   --> $DIR/dont-suggest-missing-await.rs:5:4
    |
 LL | fn take_u32(x: u32) {}
    |    ^^^^^^^^ ------
-help: consider `await`ing on the `Future`
-   |
-LL |         take_u32(x.await)
-   |                   ++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/backtrace/backtrace.rs b/tests/ui/backtrace/backtrace.rs
index 2579ff5203b..487473f4393 100644
--- a/tests/ui/backtrace/backtrace.rs
+++ b/tests/ui/backtrace/backtrace.rs
@@ -1,8 +1,7 @@
 //@ run-pass
 //@ ignore-android FIXME #17520
-//@ ignore-wasm32 spawning processes is not supported
+//@ needs-subprocess
 //@ ignore-openbsd no support for libbacktrace without filename
-//@ ignore-sgx no processes
 //@ ignore-msvc see #62897 and `backtrace-debuginfo.rs` test
 //@ ignore-fuchsia Backtraces not symbolized
 //@ compile-flags:-g
diff --git a/tests/ui/backtrace/std-backtrace.rs b/tests/ui/backtrace/std-backtrace.rs
index 57d953a8640..7ccbd46152b 100644
--- a/tests/ui/backtrace/std-backtrace.rs
+++ b/tests/ui/backtrace/std-backtrace.rs
@@ -1,8 +1,7 @@
 //@ run-pass
 //@ ignore-android FIXME #17520
-//@ ignore-wasm32 spawning processes is not supported
+//@ needs-subprocess
 //@ ignore-openbsd no support for libbacktrace without filename
-//@ ignore-sgx no processes
 //@ ignore-fuchsia Backtraces not symbolized
 //@ compile-flags:-g
 //@ compile-flags:-Cstrip=none
diff --git a/tests/ui/binop/binop-fail-3.rs b/tests/ui/binop/binop-fail-3.rs
index b1e70a1c596..4e8d7e92ab6 100644
--- a/tests/ui/binop/binop-fail-3.rs
+++ b/tests/ui/binop/binop-fail-3.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:quux
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn foo() -> ! {
     panic!("quux");
diff --git a/tests/ui/binop/binop-panic.rs b/tests/ui/binop/binop-panic.rs
index 8dbf62a922e..8173eb0d689 100644
--- a/tests/ui/binop/binop-panic.rs
+++ b/tests/ui/binop/binop-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:quux
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn my_err(s: String) -> ! {
     println!("{}", s);
diff --git a/tests/ui/borrowck/borrowck-local-borrow.rs b/tests/ui/borrowck/borrowck-local-borrow.rs
index de6ee5983c8..4d22503e37b 100644
--- a/tests/ui/borrowck/borrowck-local-borrow.rs
+++ b/tests/ui/borrowck/borrowck-local-borrow.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:panic 1
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     let x = 2;
diff --git a/tests/ui/borrowck/issue-28934.rs b/tests/ui/borrowck/issue-28934.rs
index a3ac663c5b5..64559d4cf1d 100644
--- a/tests/ui/borrowck/issue-28934.rs
+++ b/tests/ui/borrowck/issue-28934.rs
@@ -3,7 +3,7 @@
 
 //@ run-fail
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 struct Parser<'i: 't, 't>(&'i u8, &'t u8);
 
diff --git a/tests/ui/box/unit/unwind-unique.rs b/tests/ui/box/unit/unwind-unique.rs
index 512327c9af4..1da55c45ee9 100644
--- a/tests/ui/box/unit/unwind-unique.rs
+++ b/tests/ui/box/unit/unwind-unique.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ needs-unwind
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 use std::thread;
 
diff --git a/tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs b/tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs
index 80c5a8fe099..4c59df24e4b 100644
--- a/tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs
+++ b/tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs
@@ -20,7 +20,7 @@
 // It's unclear how likely such a bug is to recur, but it seems like a
 // scenario worth testing.
 
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 use std::thread;
 
diff --git a/tests/ui/closures/binder/forbid_ambig_const_infers.rs b/tests/ui/closures/binder/forbid_ambig_const_infers.rs
new file mode 100644
index 00000000000..e9d783711ee
--- /dev/null
+++ b/tests/ui/closures/binder/forbid_ambig_const_infers.rs
@@ -0,0 +1,9 @@
+#![feature(generic_arg_infer, closure_lifetime_binder)]
+
+struct Foo<const N: usize>([u32; N]);
+
+fn main() {
+    let c = for<'a> |b: &'a Foo<_>| -> u32 { b.0[0] };
+    //~^ ERROR: implicit types in closure signatures are forbidden when `for<...>` is present
+    c(&Foo([1_u32; 1]));
+}
diff --git a/tests/ui/closures/binder/forbid_ambig_const_infers.stderr b/tests/ui/closures/binder/forbid_ambig_const_infers.stderr
new file mode 100644
index 00000000000..396c9e8c916
--- /dev/null
+++ b/tests/ui/closures/binder/forbid_ambig_const_infers.stderr
@@ -0,0 +1,10 @@
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/forbid_ambig_const_infers.rs:6:33
+   |
+LL |     let c = for<'a> |b: &'a Foo<_>| -> u32 { b.0[0] };
+   |             -------             ^
+   |             |
+   |             `for<...>` is here
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/closures/binder/forbid_ambig_type_infers.rs b/tests/ui/closures/binder/forbid_ambig_type_infers.rs
new file mode 100644
index 00000000000..4e717ef3a17
--- /dev/null
+++ b/tests/ui/closures/binder/forbid_ambig_type_infers.rs
@@ -0,0 +1,9 @@
+#![feature(generic_arg_infer, closure_lifetime_binder)]
+
+struct Foo<T>(T);
+
+fn main() {
+    let c = for<'a> |b: &'a Foo<_>| -> u32 { b.0 };
+    //~^ ERROR: implicit types in closure signatures are forbidden when `for<...>` is present
+    c(&Foo(1_u32));
+}
diff --git a/tests/ui/closures/binder/forbid_ambig_type_infers.stderr b/tests/ui/closures/binder/forbid_ambig_type_infers.stderr
new file mode 100644
index 00000000000..8f19d710073
--- /dev/null
+++ b/tests/ui/closures/binder/forbid_ambig_type_infers.stderr
@@ -0,0 +1,10 @@
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/forbid_ambig_type_infers.rs:6:33
+   |
+LL |     let c = for<'a> |b: &'a Foo<_>| -> u32 { b.0 };
+   |             -------             ^
+   |             |
+   |             `for<...>` is here
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/closures/binder/forbid_const_infer.rs b/tests/ui/closures/binder/forbid_const_infer.rs
new file mode 100644
index 00000000000..f5b8bf188df
--- /dev/null
+++ b/tests/ui/closures/binder/forbid_const_infer.rs
@@ -0,0 +1,7 @@
+#![feature(generic_arg_infer, closure_lifetime_binder)]
+
+fn main() {
+    let c = for<'a> |b: &'a [u32; _]| -> u32 { b[0] };
+    //~^ ERROR: implicit types in closure signatures are forbidden when `for<...>` is present
+    c(&[1_u32; 2]);
+}
diff --git a/tests/ui/closures/binder/forbid_const_infer.stderr b/tests/ui/closures/binder/forbid_const_infer.stderr
new file mode 100644
index 00000000000..e93685d400e
--- /dev/null
+++ b/tests/ui/closures/binder/forbid_const_infer.stderr
@@ -0,0 +1,10 @@
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/forbid_const_infer.rs:4:35
+   |
+LL |     let c = for<'a> |b: &'a [u32; _]| -> u32 { b[0] };
+   |             -------               ^
+   |             |
+   |             `for<...>` is here
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/closures/diverging-closure.rs b/tests/ui/closures/diverging-closure.rs
index dda829d8af4..2c86f55cf25 100644
--- a/tests/ui/closures/diverging-closure.rs
+++ b/tests/ui/closures/diverging-closure.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:oops
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     let func = || -> ! {
diff --git a/tests/ui/command/command-argv0.rs b/tests/ui/command/command-argv0.rs
index 35625c0b334..0907e18b30c 100644
--- a/tests/ui/command/command-argv0.rs
+++ b/tests/ui/command/command-argv0.rs
@@ -1,8 +1,7 @@
 //@ run-pass
 
-//@ ignore-windows - this is a unix-specific test
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ only-unix (this is a unix-specific test)
+//@ needs-subprocess
 use std::env;
 use std::os::unix::process::CommandExt;
 use std::process::Command;
diff --git a/tests/ui/command/command-current-dir.rs b/tests/ui/command/command-current-dir.rs
index 23269e41231..e264cbe4d70 100644
--- a/tests/ui/command/command-current-dir.rs
+++ b/tests/ui/command/command-current-dir.rs
@@ -1,7 +1,6 @@
 //@ run-pass
 //@ no-prefer-dynamic We move the binary around, so do not depend dynamically on libstd
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-fuchsia Needs directory creation privilege
 
 use std::env;
diff --git a/tests/ui/command/command-exec.rs b/tests/ui/command/command-exec.rs
index d2545b0b472..77336377e88 100644
--- a/tests/ui/command/command-exec.rs
+++ b/tests/ui/command/command-exec.rs
@@ -1,13 +1,9 @@
 //@ run-pass
 
-#![allow(stable_features)]
-//@ ignore-windows - this is a unix-specific test
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ only-unix (this is a unix-specific test)
+//@ needs-subprocess
 //@ ignore-fuchsia no execvp syscall provided
 
-#![feature(process_exec)]
-
 use std::env;
 use std::os::unix::process::CommandExt;
 use std::process::Command;
diff --git a/tests/ui/command/command-pre-exec.rs b/tests/ui/command/command-pre-exec.rs
index 7242dea2775..7299f357bd0 100644
--- a/tests/ui/command/command-pre-exec.rs
+++ b/tests/ui/command/command-pre-exec.rs
@@ -1,11 +1,9 @@
 //@ run-pass
-
-#![allow(stable_features)]
-//@ ignore-windows - this is a unix-specific test
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ only-unix (this is a unix-specific test)
+//@ needs-subprocess
 //@ ignore-fuchsia no execvp syscall
-#![feature(process_exec, rustc_private)]
+
+#![feature(rustc_private)]
 
 extern crate libc;
 
diff --git a/tests/ui/command/command-setgroups.rs b/tests/ui/command/command-setgroups.rs
index c940135d844..047f06729af 100644
--- a/tests/ui/command/command-setgroups.rs
+++ b/tests/ui/command/command-setgroups.rs
@@ -1,9 +1,8 @@
 //@ run-pass
-//@ ignore-windows - this is a unix-specific test
-//@ ignore-wasm32
-//@ ignore-sgx
+//@ only-unix (this is a unix-specific test)
 //@ ignore-musl - returns dummy result for _SC_NGROUPS_MAX
 //@ ignore-nto - does not have `/bin/id`, expects groups to be i32 (not u32)
+//@ needs-subprocess
 
 #![feature(rustc_private)]
 #![feature(setgroups)]
diff --git a/tests/ui/command/command-uid-gid.rs b/tests/ui/command/command-uid-gid.rs
index 7a70a0fbd76..f54a0f50708 100644
--- a/tests/ui/command/command-uid-gid.rs
+++ b/tests/ui/command/command-uid-gid.rs
@@ -1,8 +1,7 @@
 //@ run-pass
 //@ ignore-android
-//@ ignore-emscripten
-//@ ignore-sgx
 //@ ignore-fuchsia no '/bin/sh', '/bin/ls'
+//@ needs-subprocess
 
 #![feature(rustc_private)]
 
diff --git a/tests/ui/command/issue-10626.rs b/tests/ui/command/issue-10626.rs
index f8dbb011513..d2679ec9e29 100644
--- a/tests/ui/command/issue-10626.rs
+++ b/tests/ui/command/issue-10626.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 // Make sure that if a process doesn't have its stdio/stderr descriptors set up
 // that we don't die in a large ball of fire
diff --git a/tests/ui/const-generics/generic_arg_infer/parend_infer.rs b/tests/ui/const-generics/generic_arg_infer/parend_infer.rs
new file mode 100644
index 00000000000..81c42183b38
--- /dev/null
+++ b/tests/ui/const-generics/generic_arg_infer/parend_infer.rs
@@ -0,0 +1,12 @@
+//@ check-pass
+//@ revisions: gate nogate
+#![cfg_attr(gate, feature(generic_arg_infer))]
+
+fn main() {
+    // AST Types preserve parens for pretty printing reasons. This means
+    // that this is parsed as a `TyKind::Paren(TyKind::Infer)`. Generic
+    // arg lowering therefore needs to take into account not just `TyKind::Infer`
+    // but `TyKind::Infer` wrapped in arbitrarily many `TyKind::Paren`.
+    let a: Vec<(_)> = vec![1_u8];
+    let a: Vec<(((((_)))))> = vec![1_u8];
+}
diff --git a/tests/ui/const-generics/issues/issue-62878.min.stderr b/tests/ui/const-generics/issues/issue-62878.min.stderr
index bd17d70a50b..1bb111b188d 100644
--- a/tests/ui/const-generics/issues/issue-62878.min.stderr
+++ b/tests/ui/const-generics/issues/issue-62878.min.stderr
@@ -18,19 +18,17 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
 LL + #![feature(adt_const_params)]
    |
 
-error[E0747]: type provided when a constant was expected
+error[E0658]: const arguments cannot yet be inferred with `_`
   --> $DIR/issue-62878.rs:10:11
    |
 LL |     foo::<_, { [1] }>();
    |           ^
    |
-   = help: const arguments cannot yet be inferred with `_`
-help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
-   |
-LL + #![feature(generic_arg_infer)]
-   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0747, E0770.
-For more information about an error, try `rustc --explain E0747`.
+Some errors have detailed explanations: E0658, E0770.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/tests/ui/const-generics/issues/issue-62878.rs b/tests/ui/const-generics/issues/issue-62878.rs
index 0b5269df85e..c80b46ddbc4 100644
--- a/tests/ui/const-generics/issues/issue-62878.rs
+++ b/tests/ui/const-generics/issues/issue-62878.rs
@@ -8,5 +8,5 @@ fn foo<const N: usize, const A: [u8; N]>() {}
 
 fn main() {
     foo::<_, { [1] }>();
-    //[min]~^ ERROR: type provided when a constant was expected
+    //[min]~^ ERROR: const arguments cannot yet be inferred with `_`
 }
diff --git a/tests/ui/consts/issue-29798.rs b/tests/ui/consts/issue-29798.rs
index bdabbad6491..f7470d7aac9 100644
--- a/tests/ui/consts/issue-29798.rs
+++ b/tests/ui/consts/issue-29798.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:index out of bounds: the len is 5 but the index is 5
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 const fn test(x: usize) -> i32 {
     [42;5][x]
diff --git a/tests/ui/consts/too_generic_eval_ice.stderr b/tests/ui/consts/too_generic_eval_ice.stderr
index b48be16a24c..3cc4377514a 100644
--- a/tests/ui/consts/too_generic_eval_ice.stderr
+++ b/tests/ui/consts/too_generic_eval_ice.stderr
@@ -32,13 +32,13 @@ LL |         [5; Self::HOST_SIZE] == [6; 0]
    = help: the following other types implement trait `PartialEq<Rhs>`:
              `&[T]` implements `PartialEq<Vec<U, A>>`
              `&[T]` implements `PartialEq<[U; N]>`
+             `&[u8; N]` implements `PartialEq<ByteStr>`
+             `&[u8; N]` implements `PartialEq<ByteString>`
+             `&[u8]` implements `PartialEq<ByteStr>`
+             `&[u8]` implements `PartialEq<ByteString>`
              `&mut [T]` implements `PartialEq<Vec<U, A>>`
              `&mut [T]` implements `PartialEq<[U; N]>`
-             `[T; N]` implements `PartialEq<&[U]>`
-             `[T; N]` implements `PartialEq<&mut [U]>`
-             `[T; N]` implements `PartialEq<[U; N]>`
-             `[T; N]` implements `PartialEq<[U]>`
-           and 3 others
+           and 11 others
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/coroutine/coroutine-resume-after-panic.rs b/tests/ui/coroutine/coroutine-resume-after-panic.rs
index 2745ebc6132..1aa547c2a7b 100644
--- a/tests/ui/coroutine/coroutine-resume-after-panic.rs
+++ b/tests/ui/coroutine/coroutine-resume-after-panic.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ needs-unwind
 //@ error-pattern:coroutine resumed after panicking
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 // Test that we get the correct message for resuming a panicked coroutine.
 
diff --git a/tests/ui/diagnostic-width/secondary-label-with-long-type.rs b/tests/ui/diagnostic-width/secondary-label-with-long-type.rs
new file mode 100644
index 00000000000..6ed600c48ac
--- /dev/null
+++ b/tests/ui/diagnostic-width/secondary-label-with-long-type.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: --diagnostic-width=100 -Zwrite-long-types-to-disk=yes
+//@ normalize-stderr: "long-type-\d+" -> "long-type-hash"
+type A = (i32, i32, i32, i32);
+type B = (A, A, A, A);
+type C = (B, B, B, B);
+type D = (C, C, C, C);
+
+fn foo(x: D) {
+    let () = x; //~ ERROR mismatched types
+    //~^ NOTE this expression has type `((...,
+    //~| NOTE expected `((...,
+    //~| NOTE expected tuple
+    //~| NOTE the full type name has been written to
+    //~| NOTE consider using `--verbose` to print the full type name to the console
+}
+
+fn main() {}
diff --git a/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr b/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr
new file mode 100644
index 00000000000..1e890455156
--- /dev/null
+++ b/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/secondary-label-with-long-type.rs:9:9
+   |
+LL |     let () = x;
+   |         ^^   - this expression has type `((..., ..., ..., ...), ..., ..., ...)`
+   |         |
+   |         expected `((..., ..., ..., ...), ..., ..., ...)`, found `()`
+   |
+   = note:  expected tuple `((..., ..., ..., ...), ..., ..., ...)`
+           found unit type `()`
+   = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/secondary-label-with-long-type/secondary-label-with-long-type.long-type-hash.txt'
+   = note: consider using `--verbose` to print the full type name to the console
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/did_you_mean/bad-assoc-ty.stderr b/tests/ui/did_you_mean/bad-assoc-ty.stderr
index 41039ae82a6..5fc2f7c1fe6 100644
--- a/tests/ui/did_you_mean/bad-assoc-ty.stderr
+++ b/tests/ui/did_you_mean/bad-assoc-ty.stderr
@@ -233,11 +233,6 @@ LL | fn foo<X: K<_, _>>(x: X) {}
    |             ^  ^ not allowed in type signatures
    |             |
    |             not allowed in type signatures
-   |
-help: use type parameters instead
-   |
-LL | fn foo<X: K<T, T>, T>(x: X) {}
-   |             ~  ~ +++
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/bad-assoc-ty.rs:54:34
diff --git a/tests/ui/drop/drop-order-comparisons.e2021.fixed b/tests/ui/drop/drop-order-comparisons.e2021.fixed
new file mode 100644
index 00000000000..78cf421cfbf
--- /dev/null
+++ b/tests/ui/drop/drop-order-comparisons.e2021.fixed
@@ -0,0 +1,575 @@
+// This tests various aspects of the drop order with a focus on:
+//
+// - The lifetime of temporaries with the `if let` construct (and with
+// various similar constructs) and how these lifetimes were shortened
+// for `if let` in Rust 2024.
+//
+// - The shortening of the lifetimes of temporaries in tail
+// expressions in Rust 2024.
+//
+// - The behavior of `let` chains and how this behavior compares to
+// nested `if let` expressions and chained `let .. else` statements.
+//
+// In the tests below, `Events` tracks a sequence of numbered events.
+// Calling `e.mark(..)` logs a numbered event immediately.  Calling
+// `e.ok(..)` or `e.err(..)` returns an `Ok(_)` or `Err(_)` value,
+// respectively, and logs the numbered event when that value is
+// dropped.  Calling `e.assert()` verifies that the correct number of
+// events were logged and that they were logged in the correct order.
+
+//@ revisions: e2021 e2024
+//@ [e2021] edition: 2021
+//@ [e2021] run-rustfix
+//@ [e2021] rustfix-only-machine-applicable
+//@ [e2024] edition: 2024
+//@ run-pass
+
+#![feature(let_chains)]
+#![cfg_attr(e2021, warn(rust_2024_compatibility))]
+
+fn t_bindings() {
+    let e = Events::new();
+    _ = {
+        e.mark(1);
+        let _v = e.ok(8);
+        let _v = e.ok(2).is_ok();
+        let _ = e.ok(3);
+        let Ok(_) = e.ok(4) else { unreachable!() };
+        let Ok(_) = e.ok(5).as_ref() else { unreachable!() };
+        let _v = e.ok(7);
+        e.mark(6);
+    };
+    e.assert(8);
+}
+
+fn t_tuples() {
+    let e = Events::new();
+    _ = (e.ok(1), e.ok(4).is_ok(), e.ok(2), e.ok(3).is_ok());
+    e.assert(4);
+}
+
+fn t_arrays() {
+    let e = Events::new();
+    trait Tr {}
+    impl<T> Tr for T {}
+    fn b<'a, T: 'a>(x: T) -> Box<dyn Tr + 'a> {
+        Box::new(x)
+    }
+    _ = [b(e.ok(1)), b(e.ok(4).is_ok()), b(e.ok(2)), b(e.ok(3).is_ok())];
+    e.assert(4);
+}
+
+fn t_fncalls() {
+    let e = Events::new();
+    let f = |_, _, _, _| {};
+    _ = f(e.ok(2), e.ok(4).is_ok(), e.ok(1), e.ok(3).is_ok());
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_tailexpr_bindings() {
+    let e = Events::new();
+    _ = ({
+        let _v = e.ok(2);
+        let _v = e.ok(1);
+        e.ok(5).is_ok()
+        //[e2021]~^ WARN relative drop order changing in Rust 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+    }, e.mark(3), e.ok(4));
+    e.assert(5);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_tailexpr_bindings() {
+    let e = Events::new();
+    _ = ({
+        let _v = e.ok(3);
+        let _v = e.ok(2);
+        e.ok(1).is_ok()
+    }, e.mark(4), e.ok(5));
+    e.assert(5);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_tailexpr_tuples() {
+    let e = Events::new();
+    _ = ({
+        (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok())
+        //[e2021]~^ WARN relative drop order changing in Rust 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        //[e2021]~| WARN relative drop order changing in Rust 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+    }, e.mark(1), e.ok(4));
+    e.assert(6);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_tailexpr_tuples() {
+    let e = Events::new();
+    _ = ({
+        (e.ok(4), e.ok(2).is_ok(), e.ok(5), e.ok(1).is_ok())
+    }, e.mark(3), e.ok(6));
+    e.assert(6);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_then() {
+    let e = Events::new();
+    _ = (match e.ok(4).as_ref() { Ok(_) => {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+    } _ => {}}, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_then() {
+    let e = Events::new();
+    _ = (if let Ok(_) = e.ok(2).as_ref() {
+            e.mark(1);
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_else() {
+    let e = Events::new();
+    _ = (match e.err(4).as_ref() { Ok(_) => {} _ => {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+    }}, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_else() {
+    let e = Events::new();
+    _ = (if let Ok(_) = e.err(1).as_ref() {} else {
+            e.mark(2);
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_match_then() {
+    let e = Events::new();
+    _ = (match e.ok(4).as_ref() {
+            Ok(_) => e.mark(1),
+            _ => unreachable!(),
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_match_else() {
+    let e = Events::new();
+    _ = (match e.err(4).as_ref() {
+            Ok(_) => unreachable!(),
+            _ => e.mark(1),
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_let_else_then() {
+    let e = Events::new();
+    _ = ('top: {
+         'chain: {
+            let Ok(_) = e.ok(1).as_ref() else { break 'chain };
+            // The "then" branch:
+            e.mark(2);
+            break 'top;
+        }
+        // The "else" branch:
+        unreachable!()
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_let_else_else() {
+    let e = Events::new();
+    _ = ('top: {
+         'chain: {
+            let Ok(_) = e.err(1).as_ref() else { break 'chain };
+            // The "then" branch:
+            unreachable!();
+            #[allow(unreachable_code)]
+            break 'top;
+        }
+        // The "else" branch:
+        e.mark(2);
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_then_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.ok(4).as_ref() {
+            //[e2021]~^ WARN relative drop order changing in Rust 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+        }
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_then_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.ok(2).as_ref() {
+            e.mark(1);
+        }
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_else_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        match e.err(4).as_ref() { Ok(_) => {} _ => {
+            //[e2021]~^ WARN relative drop order changing in Rust 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            //[e2021]~| WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+        }}
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_else_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.err(1).as_ref() {} else {
+            e.mark(2);
+        }
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_if_let_nested_then() {
+    let e = Events::new();
+    _ = {
+        // The unusual formatting, here and below, is to make the
+        // comparison with `let` chains more direct.
+        if e.ok(1).is_ok() {
+        if let true = e.ok(9).is_ok() {
+        if let Ok(_v) = e.ok(8) {
+        if let Ok(_) = e.ok(7) {
+        if let Ok(_) = e.ok(6).as_ref() {
+        if e.ok(2).is_ok() {
+        if let Ok(_v) = e.ok(5) {
+        if let Ok(_) = e.ok(4).as_ref() {
+            e.mark(3);
+        }}}}}}}}
+    };
+    e.assert(9);
+}
+
+#[rustfmt::skip]
+fn t_let_else_chained_then() {
+    let e = Events::new();
+    _ = 'top: {
+        'chain: {
+            if e.ok(1).is_ok() {} else { break 'chain };
+            let true = e.ok(2).is_ok() else { break 'chain };
+            let Ok(_v) = e.ok(9) else { break 'chain };
+            let Ok(_) = e.ok(3) else { break 'chain };
+            let Ok(_) = e.ok(4).as_ref() else { break 'chain };
+            if e.ok(5).is_ok() {} else { break 'chain };
+            let Ok(_v) = e.ok(8) else { break 'chain };
+            let Ok(_) = e.ok(6).as_ref() else { break 'chain };
+            // The "then" branch:
+            e.mark(7);
+            break 'top;
+        }
+        // The "else" branch:
+        unreachable!()
+    };
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_chains_then() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(9).is_ok()
+        && let Ok(_v) = e.ok(5)
+        && let Ok(_) = e.ok(8)
+        && let Ok(_) = e.ok(7).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(4)
+        && let Ok(_) = e.ok(6).as_ref() {
+            e.mark(3);
+        };
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_chains_then() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(9).is_ok()
+        && let Ok(_v) = e.ok(8)
+        && let Ok(_) = e.ok(7)
+        && let Ok(_) = e.ok(6).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(5)
+        && let Ok(_) = e.ok(4).as_ref() {
+            e.mark(3);
+        };
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_nested_else() {
+    let e = Events::new();
+    _ = if e.err(1).is_ok() {} else {
+        match e.err(9).is_ok() { true => {} _ => {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        match e.err(8) { Ok(_v) => {} _ => {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        match e.err(7) { Ok(_) => {} _ => {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        match e.err(6).as_ref() { Ok(_) => {} _ => {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        if e.err(2).is_ok() {} else {
+        match e.err(5) { Ok(_v) => {} _ => {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        match e.err(4) { Ok(_) => {} _ => {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(3);
+        }}}}}}}}}}}}}};
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_nested_else() {
+    let e = Events::new();
+    _ = if e.err(1).is_ok() {} else {
+        if let true = e.err(2).is_ok() {} else {
+        if let Ok(_v) = e.err(3) {} else {
+        if let Ok(_) = e.err(4) {} else {
+        if let Ok(_) = e.err(5).as_ref() {} else {
+        if e.err(6).is_ok() {} else {
+        if let Ok(_v) = e.err(7) {} else {
+        if let Ok(_) = e.err(8) {} else {
+            e.mark(9);
+        }}}}}}}};
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_nested_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok() {
+        if let true = e.ok(9).is_ok() {
+        if let Ok(_v) = e.ok(8) {
+        if let Ok(_) = e.ok(7) {
+        if let Ok(_) = e.ok(6).as_ref() {
+        if e.ok(2).is_ok() {
+        if let Ok(_v) = e.ok(5) {
+        match e.err(4).as_ref() { Ok(_) => {} _ => {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(3);
+        }}}}}}}}};
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_nested_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok() {
+        if let true = e.ok(9).is_ok() {
+        if let Ok(_v) = e.ok(8) {
+        if let Ok(_) = e.ok(7) {
+        if let Ok(_) = e.ok(6).as_ref() {
+        if e.ok(2).is_ok() {
+        if let Ok(_v) = e.ok(5) {
+        if let Ok(_) = e.err(3).as_ref() {} else {
+            e.mark(4);
+        }}}}}}}};
+    e.assert(9);
+}
+
+#[rustfmt::skip]
+fn t_let_else_chained_then_else() {
+    let e = Events::new();
+    _ = 'top: {
+        'chain: {
+            if e.ok(1).is_ok() {} else { break 'chain };
+            let true = e.ok(2).is_ok() else { break 'chain };
+            let Ok(_v) = e.ok(8) else { break 'chain };
+            let Ok(_) = e.ok(3) else { break 'chain };
+            let Ok(_) = e.ok(4).as_ref() else { break 'chain };
+            if e.ok(5).is_ok() {} else { break 'chain };
+            let Ok(_v) = e.ok(7) else { break 'chain };
+            let Ok(_) = e.err(6).as_ref() else { break 'chain };
+            // The "then" branch:
+            unreachable!();
+            #[allow(unreachable_code)]
+            break 'top;
+        }
+        // The "else" branch:
+        e.mark(9);
+    };
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_chains_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(9).is_ok()
+        && let Ok(_v) = e.ok(4)
+        && let Ok(_) = e.ok(8)
+        && let Ok(_) = e.ok(7).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(3)
+        && let Ok(_) = e.err(6) {} else {
+            e.mark(5);
+        };
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_chains_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(8).is_ok()
+        && let Ok(_v) = e.ok(7)
+        && let Ok(_) = e.ok(6)
+        && let Ok(_) = e.ok(5).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(4)
+        && let Ok(_) = e.err(3) {} else {
+            e.mark(9);
+        };
+    e.assert(9);
+}
+
+fn main() {
+    t_bindings();
+    t_tuples();
+    t_arrays();
+    t_fncalls();
+    t_tailexpr_bindings();
+    t_tailexpr_tuples();
+    t_if_let_then();
+    t_if_let_else();
+    t_match_then();
+    t_match_else();
+    t_let_else_then();
+    t_let_else_else();
+    t_if_let_then_tailexpr();
+    t_if_let_else_tailexpr();
+    t_if_let_nested_then();
+    t_let_else_chained_then();
+    t_if_let_chains_then();
+    t_if_let_nested_else();
+    t_if_let_nested_then_else();
+    t_let_else_chained_then_else();
+    t_if_let_chains_then_else();
+}
+
+// # Test scaffolding
+
+use core::cell::RefCell;
+use std::collections::HashSet;
+
+/// A buffer to track the order of events.
+///
+/// First, numbered events are logged into this buffer.
+///
+/// Then, `assert` is called to verify that the correct number of
+/// events were logged, and that they were logged in the expected
+/// order.
+struct Events(RefCell<Option<Vec<u64>>>);
+
+impl Events {
+    const fn new() -> Self {
+        Self(RefCell::new(Some(Vec::new())))
+    }
+    #[track_caller]
+    fn assert(&self, max: u64) {
+        let buf = &self.0;
+        let v1 = buf.borrow().as_ref().unwrap().clone();
+        let mut v2 = buf.borrow().as_ref().unwrap().clone();
+        *buf.borrow_mut() = None;
+        v2.sort();
+        let uniq_len = v2.iter().collect::<HashSet<_>>().len();
+        // Check that the sequence is sorted.
+        assert_eq!(v1, v2);
+        // Check that there are no duplicates.
+        assert_eq!(v2.len(), uniq_len);
+        // Check that the length is the expected one.
+        assert_eq!(max, uniq_len as u64);
+        // Check that the last marker is the expected one.
+        assert_eq!(v2.last().unwrap(), &max);
+    }
+    /// Return an `Ok` value that logs its drop.
+    fn ok(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> {
+        Ok(LogDrop(self, m))
+    }
+    /// Return an `Err` value that logs its drop.
+    fn err(&self, m: u64) -> Result<LogDrop, LogDrop> {
+        Err(LogDrop(self, m))
+    }
+    /// Log an event.
+    fn mark(&self, m: u64) {
+        self.0.borrow_mut().as_mut().unwrap().push(m);
+    }
+}
+
+impl Drop for Events {
+    fn drop(&mut self) {
+        if self.0.borrow().is_some() {
+            panic!("failed to call `Events::assert()`");
+        }
+    }
+}
+
+/// A type that logs its drop events.
+struct LogDrop<'b>(&'b Events, u64);
+
+impl<'b> Drop for LogDrop<'b> {
+    fn drop(&mut self) {
+        self.0.mark(self.1);
+    }
+}
diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr
new file mode 100644
index 00000000000..158d18f6882
--- /dev/null
+++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr
@@ -0,0 +1,477 @@
+warning: relative drop order changing in Rust 2024
+  --> $DIR/drop-order-comparisons.rs:76:9
+   |
+LL |       _ = ({
+   |  _________-
+LL | |         let _v = e.ok(2);
+   | |             --
+   | |             |
+   | |             `_v` calls a custom destructor
+   | |             `_v` will be dropped later as of Edition 2024
+LL | |         let _v = e.ok(1);
+   | |             --
+   | |             |
+   | |             this value will be stored in a temporary; let us call it `#2`
+   | |             `#2` will be dropped later as of Edition 2024
+LL | |         e.ok(5).is_ok()
+   | |         ^^^^^^^
+   | |         |
+   | |         this value will be stored in a temporary; let us call it `#3`
+   | |         up until Edition 2021 `#3` is dropped last but will be dropped earlier in Edition 2024
+...  |
+LL | |     }, e.mark(3), e.ok(4));
+   | |                          -
+   | |                          |
+   | |                          now the temporary value is dropped here, before the local variables in the block or statement
+   | |__________________________this value will be stored in a temporary; let us call it `#1`
+   |                            `#1` will be dropped later as of Edition 2024
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+note: `#3` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `#1` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `_v` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `#2` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+note: the lint level is defined here
+  --> $DIR/drop-order-comparisons.rs:28:25
+   |
+LL | #![cfg_attr(e2021, warn(rust_2024_compatibility))]
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(tail_expr_drop_order)]` implied by `#[warn(rust_2024_compatibility)]`
+
+warning: relative drop order changing in Rust 2024
+  --> $DIR/drop-order-comparisons.rs:100:45
+   |
+LL |       _ = ({
+   |  _________-
+LL | |         (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok())
+   | |                                             ^^^^^^^
+   | |                                             |
+   | |                                             this value will be stored in a temporary; let us call it `#2`
+   | |                                             up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024
+...  |
+LL | |     }, e.mark(1), e.ok(4));
+   | |                          -
+   | |                          |
+   | |                          now the temporary value is dropped here, before the local variables in the block or statement
+   | |__________________________this value will be stored in a temporary; let us call it `#1`
+   |                            `#1` will be dropped later as of Edition 2024
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+note: `#2` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `#1` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+warning: relative drop order changing in Rust 2024
+  --> $DIR/drop-order-comparisons.rs:100:19
+   |
+LL |       _ = ({
+   |  _________-
+LL | |         (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok())
+   | |                   ^^^^^^^
+   | |                   |
+   | |                   this value will be stored in a temporary; let us call it `#2`
+   | |                   up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024
+...  |
+LL | |     }, e.mark(1), e.ok(4));
+   | |                          -
+   | |                          |
+   | |                          now the temporary value is dropped here, before the local variables in the block or statement
+   | |__________________________this value will be stored in a temporary; let us call it `#1`
+   |                            `#1` will be dropped later as of Edition 2024
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+note: `#2` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `#1` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+warning: relative drop order changing in Rust 2024
+  --> $DIR/drop-order-comparisons.rs:221:24
+   |
+LL |       _ = ({
+   |  _________-
+LL | |         if let Ok(_) = e.ok(4).as_ref() {
+   | |                        ^^^^^^^
+   | |                        |
+   | |                        this value will be stored in a temporary; let us call it `#2`
+   | |                        up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024
+...  |
+LL | |     }, e.mark(2), e.ok(3));
+   | |                          -
+   | |                          |
+   | |                          now the temporary value is dropped here, before the local variables in the block or statement
+   | |__________________________this value will be stored in a temporary; let us call it `#1`
+   |                            `#1` will be dropped later as of Edition 2024
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+note: `#2` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `#1` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+warning: relative drop order changing in Rust 2024
+  --> $DIR/drop-order-comparisons.rs:247:24
+   |
+LL |       _ = ({
+   |  _________-
+LL | |         if let Ok(_) = e.err(4).as_ref() {} else {
+   | |                        ^^^^^^^^
+   | |                        |
+   | |                        this value will be stored in a temporary; let us call it `#2`
+   | |                        up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024
+...  |
+LL | |     }, e.mark(2), e.ok(3));
+   | |                          -
+   | |                          |
+   | |                          now the temporary value is dropped here, before the local variables in the block or statement
+   | |__________________________this value will be stored in a temporary; let us call it `#1`
+   |                            `#1` will be dropped later as of Edition 2024
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+note: `#2` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `#1` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:123:13
+   |
+LL |     _ = (if let Ok(_) = e.ok(4).as_ref() {
+   |             ^^^^^^^^^^^^-------^^^^^^^^^
+   |                         |
+   |                         this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:127:5
+   |
+LL |     }, e.mark(2), e.ok(3));
+   |     ^
+   = note: `#[warn(if_let_rescope)]` implied by `#[warn(rust_2024_compatibility)]`
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~     _ = (match e.ok(4).as_ref() { Ok(_) => {
+LL |
+LL |
+LL |             e.mark(1);
+LL ~     } _ => {}}, e.mark(2), e.ok(3));
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:145:13
+   |
+LL |     _ = (if let Ok(_) = e.err(4).as_ref() {} else {
+   |             ^^^^^^^^^^^^--------^^^^^^^^^
+   |                         |
+   |                         this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:145:44
+   |
+LL |     _ = (if let Ok(_) = e.err(4).as_ref() {} else {
+   |                                            ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~     _ = (match e.err(4).as_ref() { Ok(_) => {} _ => {
+LL |
+LL |
+LL |             e.mark(1);
+LL ~     }}, e.mark(2), e.ok(3));
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:247:12
+   |
+LL |         if let Ok(_) = e.err(4).as_ref() {} else {
+   |            ^^^^^^^^^^^^--------^^^^^^^^^
+   |                        |
+   |                        this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:247:43
+   |
+LL |         if let Ok(_) = e.err(4).as_ref() {} else {
+   |                                           ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(4).as_ref() { Ok(_) => {} _ => {
+LL |
+...
+LL |             e.mark(1);
+LL ~         }}
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:352:12
+   |
+LL |         if let true = e.err(9).is_ok() {} else {
+   |            ^^^^^^^^^^^--------^^^^^^^^
+   |                       |
+   |                       this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:352:41
+   |
+LL |         if let true = e.err(9).is_ok() {} else {
+   |                                         ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(9).is_ok() { true => {} _ => {
+LL |
+...
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:355:12
+   |
+LL |         if let Ok(_v) = e.err(8) {} else {
+   |            ^^^^^^^^^^^^^--------
+   |                         |
+   |                         this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:355:35
+   |
+LL |         if let Ok(_v) = e.err(8) {} else {
+   |                                   ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(8) { Ok(_v) => {} _ => {
+LL |
+...
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:358:12
+   |
+LL |         if let Ok(_) = e.err(7) {} else {
+   |            ^^^^^^^^^^^^--------
+   |                        |
+   |                        this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:358:34
+   |
+LL |         if let Ok(_) = e.err(7) {} else {
+   |                                  ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(7) { Ok(_) => {} _ => {
+LL |
+...
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:361:12
+   |
+LL |         if let Ok(_) = e.err(6).as_ref() {} else {
+   |            ^^^^^^^^^^^^--------^^^^^^^^^
+   |                        |
+   |                        this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:361:43
+   |
+LL |         if let Ok(_) = e.err(6).as_ref() {} else {
+   |                                           ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(6).as_ref() { Ok(_) => {} _ => {
+LL |
+...
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:365:12
+   |
+LL |         if let Ok(_v) = e.err(5) {} else {
+   |            ^^^^^^^^^^^^^--------
+   |                         |
+   |                         this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:365:35
+   |
+LL |         if let Ok(_v) = e.err(5) {} else {
+   |                                   ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(5) { Ok(_v) => {} _ => {
+LL |
+...
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:368:12
+   |
+LL |         if let Ok(_) = e.err(4) {} else {
+   |            ^^^^^^^^^^^^--------
+   |                        |
+   |                        this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:368:34
+   |
+LL |         if let Ok(_) = e.err(4) {} else {
+   |                                  ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(4) { Ok(_) => {} _ => {
+LL |
+LL |
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:404:12
+   |
+LL |         if let Ok(_) = e.err(4).as_ref() {} else {
+   |            ^^^^^^^^^^^^--------^^^^^^^^^
+   |                        |
+   |                        this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:404:43
+   |
+LL |         if let Ok(_) = e.err(4).as_ref() {} else {
+   |                                           ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(4).as_ref() { Ok(_) => {} _ => {
+LL |
+LL |
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: 15 warnings emitted
+
diff --git a/tests/ui/drop/drop-order-comparisons.rs b/tests/ui/drop/drop-order-comparisons.rs
new file mode 100644
index 00000000000..78c75a9449f
--- /dev/null
+++ b/tests/ui/drop/drop-order-comparisons.rs
@@ -0,0 +1,575 @@
+// This tests various aspects of the drop order with a focus on:
+//
+// - The lifetime of temporaries with the `if let` construct (and with
+// various similar constructs) and how these lifetimes were shortened
+// for `if let` in Rust 2024.
+//
+// - The shortening of the lifetimes of temporaries in tail
+// expressions in Rust 2024.
+//
+// - The behavior of `let` chains and how this behavior compares to
+// nested `if let` expressions and chained `let .. else` statements.
+//
+// In the tests below, `Events` tracks a sequence of numbered events.
+// Calling `e.mark(..)` logs a numbered event immediately.  Calling
+// `e.ok(..)` or `e.err(..)` returns an `Ok(_)` or `Err(_)` value,
+// respectively, and logs the numbered event when that value is
+// dropped.  Calling `e.assert()` verifies that the correct number of
+// events were logged and that they were logged in the correct order.
+
+//@ revisions: e2021 e2024
+//@ [e2021] edition: 2021
+//@ [e2021] run-rustfix
+//@ [e2021] rustfix-only-machine-applicable
+//@ [e2024] edition: 2024
+//@ run-pass
+
+#![feature(let_chains)]
+#![cfg_attr(e2021, warn(rust_2024_compatibility))]
+
+fn t_bindings() {
+    let e = Events::new();
+    _ = {
+        e.mark(1);
+        let _v = e.ok(8);
+        let _v = e.ok(2).is_ok();
+        let _ = e.ok(3);
+        let Ok(_) = e.ok(4) else { unreachable!() };
+        let Ok(_) = e.ok(5).as_ref() else { unreachable!() };
+        let _v = e.ok(7);
+        e.mark(6);
+    };
+    e.assert(8);
+}
+
+fn t_tuples() {
+    let e = Events::new();
+    _ = (e.ok(1), e.ok(4).is_ok(), e.ok(2), e.ok(3).is_ok());
+    e.assert(4);
+}
+
+fn t_arrays() {
+    let e = Events::new();
+    trait Tr {}
+    impl<T> Tr for T {}
+    fn b<'a, T: 'a>(x: T) -> Box<dyn Tr + 'a> {
+        Box::new(x)
+    }
+    _ = [b(e.ok(1)), b(e.ok(4).is_ok()), b(e.ok(2)), b(e.ok(3).is_ok())];
+    e.assert(4);
+}
+
+fn t_fncalls() {
+    let e = Events::new();
+    let f = |_, _, _, _| {};
+    _ = f(e.ok(2), e.ok(4).is_ok(), e.ok(1), e.ok(3).is_ok());
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_tailexpr_bindings() {
+    let e = Events::new();
+    _ = ({
+        let _v = e.ok(2);
+        let _v = e.ok(1);
+        e.ok(5).is_ok()
+        //[e2021]~^ WARN relative drop order changing in Rust 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+    }, e.mark(3), e.ok(4));
+    e.assert(5);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_tailexpr_bindings() {
+    let e = Events::new();
+    _ = ({
+        let _v = e.ok(3);
+        let _v = e.ok(2);
+        e.ok(1).is_ok()
+    }, e.mark(4), e.ok(5));
+    e.assert(5);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_tailexpr_tuples() {
+    let e = Events::new();
+    _ = ({
+        (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok())
+        //[e2021]~^ WARN relative drop order changing in Rust 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        //[e2021]~| WARN relative drop order changing in Rust 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+    }, e.mark(1), e.ok(4));
+    e.assert(6);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_tailexpr_tuples() {
+    let e = Events::new();
+    _ = ({
+        (e.ok(4), e.ok(2).is_ok(), e.ok(5), e.ok(1).is_ok())
+    }, e.mark(3), e.ok(6));
+    e.assert(6);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_then() {
+    let e = Events::new();
+    _ = (if let Ok(_) = e.ok(4).as_ref() {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_then() {
+    let e = Events::new();
+    _ = (if let Ok(_) = e.ok(2).as_ref() {
+            e.mark(1);
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_else() {
+    let e = Events::new();
+    _ = (if let Ok(_) = e.err(4).as_ref() {} else {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_else() {
+    let e = Events::new();
+    _ = (if let Ok(_) = e.err(1).as_ref() {} else {
+            e.mark(2);
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_match_then() {
+    let e = Events::new();
+    _ = (match e.ok(4).as_ref() {
+            Ok(_) => e.mark(1),
+            _ => unreachable!(),
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_match_else() {
+    let e = Events::new();
+    _ = (match e.err(4).as_ref() {
+            Ok(_) => unreachable!(),
+            _ => e.mark(1),
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_let_else_then() {
+    let e = Events::new();
+    _ = ('top: {
+         'chain: {
+            let Ok(_) = e.ok(1).as_ref() else { break 'chain };
+            // The "then" branch:
+            e.mark(2);
+            break 'top;
+        }
+        // The "else" branch:
+        unreachable!()
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_let_else_else() {
+    let e = Events::new();
+    _ = ('top: {
+         'chain: {
+            let Ok(_) = e.err(1).as_ref() else { break 'chain };
+            // The "then" branch:
+            unreachable!();
+            #[allow(unreachable_code)]
+            break 'top;
+        }
+        // The "else" branch:
+        e.mark(2);
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_then_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.ok(4).as_ref() {
+            //[e2021]~^ WARN relative drop order changing in Rust 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+        }
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_then_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.ok(2).as_ref() {
+            e.mark(1);
+        }
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_else_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.err(4).as_ref() {} else {
+            //[e2021]~^ WARN relative drop order changing in Rust 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            //[e2021]~| WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+        }
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_else_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.err(1).as_ref() {} else {
+            e.mark(2);
+        }
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_if_let_nested_then() {
+    let e = Events::new();
+    _ = {
+        // The unusual formatting, here and below, is to make the
+        // comparison with `let` chains more direct.
+        if e.ok(1).is_ok() {
+        if let true = e.ok(9).is_ok() {
+        if let Ok(_v) = e.ok(8) {
+        if let Ok(_) = e.ok(7) {
+        if let Ok(_) = e.ok(6).as_ref() {
+        if e.ok(2).is_ok() {
+        if let Ok(_v) = e.ok(5) {
+        if let Ok(_) = e.ok(4).as_ref() {
+            e.mark(3);
+        }}}}}}}}
+    };
+    e.assert(9);
+}
+
+#[rustfmt::skip]
+fn t_let_else_chained_then() {
+    let e = Events::new();
+    _ = 'top: {
+        'chain: {
+            if e.ok(1).is_ok() {} else { break 'chain };
+            let true = e.ok(2).is_ok() else { break 'chain };
+            let Ok(_v) = e.ok(9) else { break 'chain };
+            let Ok(_) = e.ok(3) else { break 'chain };
+            let Ok(_) = e.ok(4).as_ref() else { break 'chain };
+            if e.ok(5).is_ok() {} else { break 'chain };
+            let Ok(_v) = e.ok(8) else { break 'chain };
+            let Ok(_) = e.ok(6).as_ref() else { break 'chain };
+            // The "then" branch:
+            e.mark(7);
+            break 'top;
+        }
+        // The "else" branch:
+        unreachable!()
+    };
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_chains_then() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(9).is_ok()
+        && let Ok(_v) = e.ok(5)
+        && let Ok(_) = e.ok(8)
+        && let Ok(_) = e.ok(7).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(4)
+        && let Ok(_) = e.ok(6).as_ref() {
+            e.mark(3);
+        };
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_chains_then() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(9).is_ok()
+        && let Ok(_v) = e.ok(8)
+        && let Ok(_) = e.ok(7)
+        && let Ok(_) = e.ok(6).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(5)
+        && let Ok(_) = e.ok(4).as_ref() {
+            e.mark(3);
+        };
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_nested_else() {
+    let e = Events::new();
+    _ = if e.err(1).is_ok() {} else {
+        if let true = e.err(9).is_ok() {} else {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        if let Ok(_v) = e.err(8) {} else {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        if let Ok(_) = e.err(7) {} else {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        if let Ok(_) = e.err(6).as_ref() {} else {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        if e.err(2).is_ok() {} else {
+        if let Ok(_v) = e.err(5) {} else {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        if let Ok(_) = e.err(4) {} else {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(3);
+        }}}}}}}};
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_nested_else() {
+    let e = Events::new();
+    _ = if e.err(1).is_ok() {} else {
+        if let true = e.err(2).is_ok() {} else {
+        if let Ok(_v) = e.err(3) {} else {
+        if let Ok(_) = e.err(4) {} else {
+        if let Ok(_) = e.err(5).as_ref() {} else {
+        if e.err(6).is_ok() {} else {
+        if let Ok(_v) = e.err(7) {} else {
+        if let Ok(_) = e.err(8) {} else {
+            e.mark(9);
+        }}}}}}}};
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_nested_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok() {
+        if let true = e.ok(9).is_ok() {
+        if let Ok(_v) = e.ok(8) {
+        if let Ok(_) = e.ok(7) {
+        if let Ok(_) = e.ok(6).as_ref() {
+        if e.ok(2).is_ok() {
+        if let Ok(_v) = e.ok(5) {
+        if let Ok(_) = e.err(4).as_ref() {} else {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(3);
+        }}}}}}}};
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_nested_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok() {
+        if let true = e.ok(9).is_ok() {
+        if let Ok(_v) = e.ok(8) {
+        if let Ok(_) = e.ok(7) {
+        if let Ok(_) = e.ok(6).as_ref() {
+        if e.ok(2).is_ok() {
+        if let Ok(_v) = e.ok(5) {
+        if let Ok(_) = e.err(3).as_ref() {} else {
+            e.mark(4);
+        }}}}}}}};
+    e.assert(9);
+}
+
+#[rustfmt::skip]
+fn t_let_else_chained_then_else() {
+    let e = Events::new();
+    _ = 'top: {
+        'chain: {
+            if e.ok(1).is_ok() {} else { break 'chain };
+            let true = e.ok(2).is_ok() else { break 'chain };
+            let Ok(_v) = e.ok(8) else { break 'chain };
+            let Ok(_) = e.ok(3) else { break 'chain };
+            let Ok(_) = e.ok(4).as_ref() else { break 'chain };
+            if e.ok(5).is_ok() {} else { break 'chain };
+            let Ok(_v) = e.ok(7) else { break 'chain };
+            let Ok(_) = e.err(6).as_ref() else { break 'chain };
+            // The "then" branch:
+            unreachable!();
+            #[allow(unreachable_code)]
+            break 'top;
+        }
+        // The "else" branch:
+        e.mark(9);
+    };
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_chains_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(9).is_ok()
+        && let Ok(_v) = e.ok(4)
+        && let Ok(_) = e.ok(8)
+        && let Ok(_) = e.ok(7).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(3)
+        && let Ok(_) = e.err(6) {} else {
+            e.mark(5);
+        };
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_chains_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(8).is_ok()
+        && let Ok(_v) = e.ok(7)
+        && let Ok(_) = e.ok(6)
+        && let Ok(_) = e.ok(5).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(4)
+        && let Ok(_) = e.err(3) {} else {
+            e.mark(9);
+        };
+    e.assert(9);
+}
+
+fn main() {
+    t_bindings();
+    t_tuples();
+    t_arrays();
+    t_fncalls();
+    t_tailexpr_bindings();
+    t_tailexpr_tuples();
+    t_if_let_then();
+    t_if_let_else();
+    t_match_then();
+    t_match_else();
+    t_let_else_then();
+    t_let_else_else();
+    t_if_let_then_tailexpr();
+    t_if_let_else_tailexpr();
+    t_if_let_nested_then();
+    t_let_else_chained_then();
+    t_if_let_chains_then();
+    t_if_let_nested_else();
+    t_if_let_nested_then_else();
+    t_let_else_chained_then_else();
+    t_if_let_chains_then_else();
+}
+
+// # Test scaffolding
+
+use core::cell::RefCell;
+use std::collections::HashSet;
+
+/// A buffer to track the order of events.
+///
+/// First, numbered events are logged into this buffer.
+///
+/// Then, `assert` is called to verify that the correct number of
+/// events were logged, and that they were logged in the expected
+/// order.
+struct Events(RefCell<Option<Vec<u64>>>);
+
+impl Events {
+    const fn new() -> Self {
+        Self(RefCell::new(Some(Vec::new())))
+    }
+    #[track_caller]
+    fn assert(&self, max: u64) {
+        let buf = &self.0;
+        let v1 = buf.borrow().as_ref().unwrap().clone();
+        let mut v2 = buf.borrow().as_ref().unwrap().clone();
+        *buf.borrow_mut() = None;
+        v2.sort();
+        let uniq_len = v2.iter().collect::<HashSet<_>>().len();
+        // Check that the sequence is sorted.
+        assert_eq!(v1, v2);
+        // Check that there are no duplicates.
+        assert_eq!(v2.len(), uniq_len);
+        // Check that the length is the expected one.
+        assert_eq!(max, uniq_len as u64);
+        // Check that the last marker is the expected one.
+        assert_eq!(v2.last().unwrap(), &max);
+    }
+    /// Return an `Ok` value that logs its drop.
+    fn ok(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> {
+        Ok(LogDrop(self, m))
+    }
+    /// Return an `Err` value that logs its drop.
+    fn err(&self, m: u64) -> Result<LogDrop, LogDrop> {
+        Err(LogDrop(self, m))
+    }
+    /// Log an event.
+    fn mark(&self, m: u64) {
+        self.0.borrow_mut().as_mut().unwrap().push(m);
+    }
+}
+
+impl Drop for Events {
+    fn drop(&mut self) {
+        if self.0.borrow().is_some() {
+            panic!("failed to call `Events::assert()`");
+        }
+    }
+}
+
+/// A type that logs its drop events.
+struct LogDrop<'b>(&'b Events, u64);
+
+impl<'b> Drop for LogDrop<'b> {
+    fn drop(&mut self) {
+        self.0.mark(self.1);
+    }
+}
diff --git a/tests/ui/drop/drop-trait-enum.rs b/tests/ui/drop/drop-trait-enum.rs
index 91b5bcdf730..5a88d959ec6 100644
--- a/tests/ui/drop/drop-trait-enum.rs
+++ b/tests/ui/drop/drop-trait-enum.rs
@@ -2,7 +2,7 @@
 #![allow(dead_code)]
 #![allow(unused_assignments)]
 #![allow(unused_variables)]
-//@ ignore-emscripten no threads support
+//@ needs-threads
 //@ needs-unwind
 
 use std::thread;
diff --git a/tests/ui/drop/terminate-in-initializer.rs b/tests/ui/drop/terminate-in-initializer.rs
index 23169aaf65b..24ec39fe096 100644
--- a/tests/ui/drop/terminate-in-initializer.rs
+++ b/tests/ui/drop/terminate-in-initializer.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ needs-unwind
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 // Issue #787
 // Don't try to clean up uninitialized locals
diff --git a/tests/ui/expr/if/expr-if-panic-fn.rs b/tests/ui/expr/if/expr-if-panic-fn.rs
index 4f3d7fd48e3..0b4742d4a89 100644
--- a/tests/ui/expr/if/expr-if-panic-fn.rs
+++ b/tests/ui/expr/if/expr-if-panic-fn.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn f() -> ! {
     panic!()
diff --git a/tests/ui/expr/if/expr-if-panic.rs b/tests/ui/expr/if/expr-if-panic.rs
index 0b43d1d6b00..2f35878e844 100644
--- a/tests/ui/expr/if/expr-if-panic.rs
+++ b/tests/ui/expr/if/expr-if-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     let _x = if false {
diff --git a/tests/ui/expr/if/if-check-panic.rs b/tests/ui/expr/if/if-check-panic.rs
index 4b400deaca4..eb0413f42fc 100644
--- a/tests/ui/expr/if/if-check-panic.rs
+++ b/tests/ui/expr/if/if-check-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:Number is odd
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn even(x: usize) -> bool {
     if x < 2 {
diff --git a/tests/ui/expr/if/if-cond-bot.rs b/tests/ui/expr/if/if-cond-bot.rs
index ddb5559ffca..56bd5ec35f9 100644
--- a/tests/ui/expr/if/if-cond-bot.rs
+++ b/tests/ui/expr/if/if-cond-bot.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:quux
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn my_err(s: String) -> ! {
     println!("{}", s);
diff --git a/tests/ui/extern/issue-18576.rs b/tests/ui/extern/issue-18576.rs
index 0a98e85e484..6b41fe73631 100644
--- a/tests/ui/extern/issue-18576.rs
+++ b/tests/ui/extern/issue-18576.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:stop
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 // #18576
 // Make sure that calling an extern function pointer in an unreachable
diff --git a/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs b/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs
index e9471d207da..1cd52b70315 100644
--- a/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs
+++ b/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ needs-unwind
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 // rust-lang/rust#64655: with panic=unwind, a panic from a subroutine
 // should still run destructors as it unwinds the stack. However,
diff --git a/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs b/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs
index 9486b5f1178..a44eb3828d0 100644
--- a/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs
+++ b/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ needs-unwind
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 // rust-lang/rust#64655: with panic=unwind, a panic from a subroutine
 // should still run destructors as it unwinds the stack. However,
diff --git a/tests/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr b/tests/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr
index 96fb4a53609..73e6988b09c 100644
--- a/tests/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr
+++ b/tests/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr
@@ -8,17 +8,15 @@ LL |     let _y: [u8; _] = [0; 3];
    = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0747]: type provided when a constant was expected
+error[E0658]: const arguments cannot yet be inferred with `_`
   --> $DIR/feature-gate-generic_arg_infer.rs:18:20
    |
-LL |     let _x = foo::<_>([1,2]);
+LL |     let _x = foo::<_>([1, 2]);
    |                    ^
    |
-   = help: const arguments cannot yet be inferred with `_`
-help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
-   |
-LL + #![feature(generic_arg_infer)]
-   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: using `_` for array lengths is unstable
   --> $DIR/feature-gate-generic_arg_infer.rs:11:27
@@ -32,5 +30,4 @@ LL |     let _x: [u8; 3] = [0; _];
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0658, E0747.
-For more information about an error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-generic_arg_infer.rs b/tests/ui/feature-gates/feature-gate-generic_arg_infer.rs
index de4b7078ea6..147978b0557 100644
--- a/tests/ui/feature-gates/feature-gate-generic_arg_infer.rs
+++ b/tests/ui/feature-gates/feature-gate-generic_arg_infer.rs
@@ -4,7 +4,7 @@
 #![cfg_attr(feature, feature(generic_arg_infer))]
 
 fn foo<const N: usize>(_: [u8; N]) -> [u8; N] {
-  [0; N]
+    [0; N]
 }
 
 fn bar() {
@@ -15,7 +15,7 @@ fn bar() {
 }
 
 fn main() {
-    let _x = foo::<_>([1,2]);
-    //[normal]~^ ERROR: type provided when a constant was expected
+    let _x = foo::<_>([1, 2]);
+    //[normal]~^ ERROR: const arguments cannot yet be inferred with `_`
     bar();
 }
diff --git a/tests/ui/fn/expr-fn-panic.rs b/tests/ui/fn/expr-fn-panic.rs
index 23946b7533d..d726aac2a4c 100644
--- a/tests/ui/fn/expr-fn-panic.rs
+++ b/tests/ui/fn/expr-fn-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn f() -> ! {
     panic!()
diff --git a/tests/ui/generics/issue-79605.stderr b/tests/ui/generics/issue-79605.stderr
index 67fed200f96..049f77a6584 100644
--- a/tests/ui/generics/issue-79605.stderr
+++ b/tests/ui/generics/issue-79605.stderr
@@ -3,11 +3,6 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures
    |
 LL | impl X<'_, _> {}
    |            ^ not allowed in type signatures
-   |
-help: use type parameters instead
-   |
-LL | impl<T> X<'_, T> {}
-   |     +++       ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/hashmap/hashmap-capacity-overflow.rs b/tests/ui/hashmap/hashmap-capacity-overflow.rs
index 91aebc3bbba..502dbe9fa93 100644
--- a/tests/ui/hashmap/hashmap-capacity-overflow.rs
+++ b/tests/ui/hashmap/hashmap-capacity-overflow.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:capacity overflow
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 use std::collections::hash_map::HashMap;
 use std::mem::size_of;
diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs
index a44ed9e5ef5..34548e2487e 100644
--- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs
+++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs
@@ -43,9 +43,9 @@ fn main() {
     }
 
     foo(bar, "string", |s| s.len() == 5);
-    //~^ ERROR implementation of `FnOnce` is not general enough
-    //~| ERROR implementation of `FnOnce` is not general enough
+    //~^ ERROR implementation of `Parser` is not general enough
+    //~| ERROR implementation of `Parser` is not general enough
     foo(baz, "string", |s| s.0.len() == 5);
-    //~^ ERROR implementation of `FnOnce` is not general enough
-    //~| ERROR implementation of `FnOnce` is not general enough
+    //~^ ERROR implementation of `Parser` is not general enough
+    //~| ERROR implementation of `Parser` is not general enough
 }
diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr
index b2bb417a8f0..23fc6e2f7f4 100644
--- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr
@@ -1,39 +1,39 @@
-error: implementation of `FnOnce` is not general enough
+error: implementation of `Parser` is not general enough
   --> $DIR/issue-71955.rs:45:5
    |
 LL |     foo(bar, "string", |s| s.len() == 5);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Parser` is not general enough
    |
-   = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`...
-   = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2`
+   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
 
-error: implementation of `FnOnce` is not general enough
+error: implementation of `Parser` is not general enough
   --> $DIR/issue-71955.rs:45:5
    |
 LL |     foo(bar, "string", |s| s.len() == 5);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Parser` is not general enough
    |
-   = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`...
-   = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2`
+   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: implementation of `FnOnce` is not general enough
+error: implementation of `Parser` is not general enough
   --> $DIR/issue-71955.rs:48:5
    |
 LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Parser` is not general enough
    |
-   = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`...
-   = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2`
+   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
 
-error: implementation of `FnOnce` is not general enough
+error: implementation of `Parser` is not general enough
   --> $DIR/issue-71955.rs:48:5
    |
 LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Parser` is not general enough
    |
-   = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`...
-   = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2`
+   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/impl-trait/issue-102605.stderr b/tests/ui/impl-trait/issue-102605.stderr
index dcb22797173..ed6663fa61f 100644
--- a/tests/ui/impl-trait/issue-102605.stderr
+++ b/tests/ui/impl-trait/issue-102605.stderr
@@ -14,20 +14,11 @@ LL |     convert_result(foo())
    |     |
    |     arguments to this function are incorrect
    |
-note: calling an async function returns a future
-  --> $DIR/issue-102605.rs:13:20
-   |
-LL |     convert_result(foo())
-   |                    ^^^^^
 note: function defined here
   --> $DIR/issue-102605.rs:7:4
    |
 LL | fn convert_result<T, E>(r: Result<T, E>) -> Option<T> {
    |    ^^^^^^^^^^^^^^       ---------------
-help: consider `await`ing on the `Future`
-   |
-LL |     convert_result(foo().await)
-   |                         ++++++
 help: try wrapping the expression in `Err`
    |
 LL |     convert_result(Err(foo()))
diff --git a/tests/ui/imports/glob-use-std.rs b/tests/ui/imports/glob-use-std.rs
index b625543da81..d2af816e24f 100644
--- a/tests/ui/imports/glob-use-std.rs
+++ b/tests/ui/imports/glob-use-std.rs
@@ -2,7 +2,7 @@
 
 //@ run-fail
 //@ error-pattern:panic works
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 use std::*;
 
diff --git a/tests/ui/inference/issue-72616.stderr b/tests/ui/inference/issue-72616.stderr
index 02c92c1c11d..a26f9a1ff56 100644
--- a/tests/ui/inference/issue-72616.stderr
+++ b/tests/ui/inference/issue-72616.stderr
@@ -6,11 +6,14 @@ LL |         if String::from("a") == "a".try_into().unwrap() {}
    |                              |
    |                              type must be known at this point
    |
-   = note: multiple `impl`s satisfying `String: PartialEq<_>` found in the `alloc` crate:
-           - impl PartialEq for String;
-           - impl<'a, 'b> PartialEq<&'a str> for String;
-           - impl<'a, 'b> PartialEq<Cow<'a, str>> for String;
-           - impl<'a, 'b> PartialEq<str> for String;
+   = note: cannot satisfy `String: PartialEq<_>`
+   = help: the following types implement trait `PartialEq<Rhs>`:
+             `String` implements `PartialEq<&str>`
+             `String` implements `PartialEq<ByteStr>`
+             `String` implements `PartialEq<ByteString>`
+             `String` implements `PartialEq<Cow<'_, str>>`
+             `String` implements `PartialEq<str>`
+             `String` implements `PartialEq`
 help: try using a fully qualified path to specify the expected types
    |
 LL |         if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
diff --git a/tests/ui/inference/issue-72690.stderr b/tests/ui/inference/issue-72690.stderr
index 6391672f861..2d09f667ae2 100644
--- a/tests/ui/inference/issue-72690.stderr
+++ b/tests/ui/inference/issue-72690.stderr
@@ -15,6 +15,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -41,6 +42,7 @@ LL |     |x| String::from("x".as_ref());
    |                          ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -57,6 +59,7 @@ LL |     let _ = "x".as_ref();
    |         ^       ------ type must be known at this point
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -83,6 +86,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -109,6 +113,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -135,6 +140,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -161,6 +167,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -187,6 +194,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -213,6 +221,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
diff --git a/tests/ui/intrinsics/panic-uninitialized-zeroed.rs b/tests/ui/intrinsics/panic-uninitialized-zeroed.rs
index 67b9832d601..346a94c37dd 100644
--- a/tests/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/tests/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -1,11 +1,10 @@
+// ignore-tidy-linelength
+//! This test checks panic emitted from `mem::{uninitialized,zeroed}`.
 //@ run-pass
 //@ revisions: default strict
 //@ [strict]compile-flags: -Zstrict-init-checks
-// ignore-tidy-linelength
-//@ ignore-wasm32 spawning processes is not supported
-//@ ignore-sgx no processes
-//
-// This test checks panic emitted from `mem::{uninitialized,zeroed}`.
+//@ needs-subprocess
+
 #![allow(deprecated, invalid_value)]
 #![feature(never_type)]
 
diff --git a/tests/ui/intrinsics/reify-intrinsic.rs b/tests/ui/intrinsics/reify-intrinsic.rs
index 0d047ccf4a3..5b2324235c1 100644
--- a/tests/ui/intrinsics/reify-intrinsic.rs
+++ b/tests/ui/intrinsics/reify-intrinsic.rs
@@ -3,17 +3,17 @@
 #![feature(core_intrinsics, intrinsics)]
 
 fn a() {
-    let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute;
+    let _: unsafe fn(isize) -> usize = std::mem::transmute;
     //~^ ERROR cannot coerce
 }
 
 fn b() {
-    let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize;
+    let _ = std::mem::transmute as unsafe fn(isize) -> usize;
     //~^ ERROR casting
 }
 
 fn c() {
-    let _: [unsafe extern "rust-intrinsic" fn(f32) -> f32; 2] = [
+    let _: [unsafe fn(f32) -> f32; 2] = [
         std::intrinsics::floorf32, //~ ERROR cannot coerce
         std::intrinsics::log2f32,
     ];
diff --git a/tests/ui/intrinsics/reify-intrinsic.stderr b/tests/ui/intrinsics/reify-intrinsic.stderr
index aea6d263a72..aea6f838e0d 100644
--- a/tests/ui/intrinsics/reify-intrinsic.stderr
+++ b/tests/ui/intrinsics/reify-intrinsic.stderr
@@ -1,19 +1,19 @@
 error[E0308]: cannot coerce intrinsics to function pointers
-  --> $DIR/reify-intrinsic.rs:6:64
+  --> $DIR/reify-intrinsic.rs:6:40
    |
-LL |     let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute;
-   |            -------------------------------------------------   ^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
+LL |     let _: unsafe fn(isize) -> usize = std::mem::transmute;
+   |            -------------------------   ^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
    |            |
    |            expected due to this
    |
-   = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(isize) -> usize`
+   = note: expected fn pointer `unsafe fn(isize) -> usize`
                  found fn item `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}`
 
-error[E0606]: casting `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid
+error[E0606]: casting `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe fn(isize) -> usize` is invalid
   --> $DIR/reify-intrinsic.rs:11:13
    |
-LL |     let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _ = std::mem::transmute as unsafe fn(isize) -> usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: cannot coerce intrinsics to function pointers
   --> $DIR/reify-intrinsic.rs:17:9
@@ -21,7 +21,7 @@ error[E0308]: cannot coerce intrinsics to function pointers
 LL |         std::intrinsics::floorf32,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
    |
-   = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(_) -> _`
+   = note: expected fn pointer `unsafe fn(_) -> _`
                  found fn item `unsafe fn(_) -> _ {floorf32}`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/issues/issue-12920.rs b/tests/ui/issues/issue-12920.rs
index 7f453e499d4..f3b1b643c45 100644
--- a/tests/ui/issues/issue-12920.rs
+++ b/tests/ui/issues/issue-12920.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 pub fn main() {
     panic!();
diff --git a/tests/ui/issues/issue-13202.rs b/tests/ui/issues/issue-13202.rs
index 89205fc7fd1..99ffba3fba5 100644
--- a/tests/ui/issues/issue-13202.rs
+++ b/tests/ui/issues/issue-13202.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:bad input
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     Some("foo").unwrap_or(panic!("bad input")).to_string();
diff --git a/tests/ui/issues/issue-20971.rs b/tests/ui/issues/issue-20971.rs
index 377a3d9ea30..31dd9101919 100644
--- a/tests/ui/issues/issue-20971.rs
+++ b/tests/ui/issues/issue-20971.rs
@@ -2,7 +2,7 @@
 
 //@ run-fail
 //@ error-pattern:Hello, world!
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 pub trait Parser {
     type Input;
diff --git a/tests/ui/issues/issue-2190-1.rs b/tests/ui/issues/issue-2190-1.rs
index 8db4a84aac8..e4e4bf9dbbe 100644
--- a/tests/ui/issues/issue-2190-1.rs
+++ b/tests/ui/issues/issue-2190-1.rs
@@ -1,20 +1,16 @@
-//@ run-pass
-#![allow(unused_must_use)]
-#![allow(non_upper_case_globals)]
-
-//@ ignore-emscripten no threads
+//@ check-pass
 
 use std::thread::Builder;
 
-static generations: usize = 1024+256+128+49;
+static GENERATIONS: usize = 1024+256+128+49;
 
 fn spawn(mut f: Box<dyn FnMut() + 'static + Send>) {
-    Builder::new().stack_size(32 * 1024).spawn(move|| f());
+    Builder::new().stack_size(32 * 1024).spawn(move || f());
 }
 
 fn child_no(x: usize) -> Box<dyn FnMut() + 'static + Send> {
-    Box::new(move|| {
-        if x < generations {
+    Box::new(move || {
+        if x < GENERATIONS {
             spawn(child_no(x+1));
         }
     })
diff --git a/tests/ui/issues/issue-23354-2.rs b/tests/ui/issues/issue-23354-2.rs
index 90de1276cc6..a296477215e 100644
--- a/tests/ui/issues/issue-23354-2.rs
+++ b/tests/ui/issues/issue-23354-2.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:panic evaluated
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #[allow(unused_variables)]
 fn main() {
diff --git a/tests/ui/issues/issue-23354.rs b/tests/ui/issues/issue-23354.rs
index 31783842dac..eff5f3d2714 100644
--- a/tests/ui/issues/issue-23354.rs
+++ b/tests/ui/issues/issue-23354.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:panic evaluated
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #[allow(unused_variables)]
 fn main() {
diff --git a/tests/ui/issues/issue-2470-bounds-check-overflow.rs b/tests/ui/issues/issue-2470-bounds-check-overflow.rs
index 241bc8fda9c..4f300454dcb 100644
--- a/tests/ui/issues/issue-2470-bounds-check-overflow.rs
+++ b/tests/ui/issues/issue-2470-bounds-check-overflow.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:index out of bounds
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 use std::mem;
 
diff --git a/tests/ui/issues/issue-25089.rs b/tests/ui/issues/issue-25089.rs
index ea9ab290904..929738c3e79 100644
--- a/tests/ui/issues/issue-25089.rs
+++ b/tests/ui/issues/issue-25089.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ needs-unwind
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 use std::thread;
 
diff --git a/tests/ui/issues/issue-26655.rs b/tests/ui/issues/issue-26655.rs
index 7f1858fdb7d..416472b0b26 100644
--- a/tests/ui/issues/issue-26655.rs
+++ b/tests/ui/issues/issue-26655.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ needs-unwind
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 // Check that the destructors of simple enums are run on unwinding
 
diff --git a/tests/ui/issues/issue-2761.rs b/tests/ui/issues/issue-2761.rs
index b44a24e09f2..6df7a5118b8 100644
--- a/tests/ui/issues/issue-2761.rs
+++ b/tests/ui/issues/issue-2761.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:custom message
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     assert!(false, "custom message");
diff --git a/tests/ui/issues/issue-29485.rs b/tests/ui/issues/issue-29485.rs
index 56865d0e5db..a44bcd49c6a 100644
--- a/tests/ui/issues/issue-29485.rs
+++ b/tests/ui/issues/issue-29485.rs
@@ -2,7 +2,7 @@
 #![allow(unused_attributes)]
 //@ aux-build:issue-29485.rs
 //@ needs-unwind
-//@ ignore-emscripten no threads
+//@ needs-threads
 
 #[feature(recover)]
 
diff --git a/tests/ui/issues/issue-30018-panic.rs b/tests/ui/issues/issue-30018-panic.rs
index f5482d7c741..591848b6f7b 100644
--- a/tests/ui/issues/issue-30018-panic.rs
+++ b/tests/ui/issues/issue-30018-panic.rs
@@ -5,7 +5,7 @@
 // SIGTRAP injected by the drop-flag consistency checking.
 
 //@ needs-unwind
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 struct Foo;
 
diff --git a/tests/ui/issues/issue-3029.rs b/tests/ui/issues/issue-3029.rs
index a070578969c..22d0906ccf7 100644
--- a/tests/ui/issues/issue-3029.rs
+++ b/tests/ui/issues/issue-3029.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:so long
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #![allow(unreachable_code)]
 
diff --git a/tests/ui/issues/issue-30380.rs b/tests/ui/issues/issue-30380.rs
index 534bb3423d0..49fce3d150c 100644
--- a/tests/ui/issues/issue-30380.rs
+++ b/tests/ui/issues/issue-30380.rs
@@ -3,7 +3,7 @@
 
 //@ run-fail
 //@ error-pattern:panicking destructors ftw!
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 struct Observer<'a>(&'a mut FilledOnDrop);
 
diff --git a/tests/ui/issues/issue-33770.rs b/tests/ui/issues/issue-33770.rs
index 0fa91ac91c4..814e8f37176 100644
--- a/tests/ui/issues/issue-33770.rs
+++ b/tests/ui/issues/issue-33770.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::process::{Command, Stdio};
 use std::env;
diff --git a/tests/ui/issues/issue-38763.rs b/tests/ui/issues/issue-38763.rs
index 05cd648dcfe..87c758db172 100644
--- a/tests/ui/issues/issue-38763.rs
+++ b/tests/ui/issues/issue-38763.rs
@@ -1,5 +1,5 @@
 //@ run-pass
-//@ ignore-emscripten
+//@ needs-threads
 
 #[repr(C)]
 pub struct Foo(i128);
diff --git a/tests/ui/issues/issue-44216-add-system-time.rs b/tests/ui/issues/issue-44216-add-system-time.rs
index 207f72fade8..3838d28e33d 100644
--- a/tests/ui/issues/issue-44216-add-system-time.rs
+++ b/tests/ui/issues/issue-44216-add-system-time.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:overflow
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 use std::time::{Duration, SystemTime};
 
diff --git a/tests/ui/issues/issue-44216-sub-instant.rs b/tests/ui/issues/issue-44216-sub-instant.rs
index 2457d2aaa04..19cd12e685f 100644
--- a/tests/ui/issues/issue-44216-sub-instant.rs
+++ b/tests/ui/issues/issue-44216-sub-instant.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:overflow
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 use std::time::{Instant, Duration};
 
diff --git a/tests/ui/issues/issue-44216-sub-system-time.rs b/tests/ui/issues/issue-44216-sub-system-time.rs
index 7e33f227933..bd4f66f3e16 100644
--- a/tests/ui/issues/issue-44216-sub-system-time.rs
+++ b/tests/ui/issues/issue-44216-sub-system-time.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:overflow
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 use std::time::{Duration, SystemTime};
 
diff --git a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs
index 6af6655149b..d7c7b2e2414 100644
--- a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs
+++ b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs
@@ -1,5 +1,6 @@
 //@ revisions: edition2021 edition2024
-//@ ignore-wasm no panic or subprocess support
+//@ ignore-wasm no panic support
+//@ needs-subprocess
 //@ [edition2024] edition: 2024
 //@ run-pass
 //@ needs-unwind
diff --git a/tests/ui/loops/for-each-loop-panic.rs b/tests/ui/loops/for-each-loop-panic.rs
index 04784cac8f2..79cfca93e0e 100644
--- a/tests/ui/loops/for-each-loop-panic.rs
+++ b/tests/ui/loops/for-each-loop-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:moop
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     for _ in 0_usize..10_usize {
diff --git a/tests/ui/macros/assert-as-macro.rs b/tests/ui/macros/assert-as-macro.rs
index 391b056292f..c18a3d89fb6 100644
--- a/tests/ui/macros/assert-as-macro.rs
+++ b/tests/ui/macros/assert-as-macro.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:assertion failed: 1 == 2
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     assert!(1 == 2);
diff --git a/tests/ui/macros/assert-eq-macro-msg.rs b/tests/ui/macros/assert-eq-macro-msg.rs
index 39eeefeeef9..9ef7552cc7b 100644
--- a/tests/ui/macros/assert-eq-macro-msg.rs
+++ b/tests/ui/macros/assert-eq-macro-msg.rs
@@ -2,7 +2,7 @@
 //@ error-pattern:assertion `left == right` failed: 1 + 1 definitely should be 3
 //@ error-pattern:  left: 2
 //@ error-pattern: right: 3
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     assert_eq!(1 + 1, 3, "1 + 1 definitely should be 3");
diff --git a/tests/ui/macros/assert-eq-macro-panic.rs b/tests/ui/macros/assert-eq-macro-panic.rs
index 22c3a8a634f..3c46e2798d1 100644
--- a/tests/ui/macros/assert-eq-macro-panic.rs
+++ b/tests/ui/macros/assert-eq-macro-panic.rs
@@ -2,7 +2,7 @@
 //@ error-pattern:assertion `left == right` failed
 //@ error-pattern:  left: 14
 //@ error-pattern: right: 15
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     assert_eq!(14, 15);
diff --git a/tests/ui/macros/assert-macro-explicit.rs b/tests/ui/macros/assert-macro-explicit.rs
index 167581d2525..b14a182a876 100644
--- a/tests/ui/macros/assert-macro-explicit.rs
+++ b/tests/ui/macros/assert-macro-explicit.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:assertion failed: false
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     assert!(false);
diff --git a/tests/ui/macros/assert-macro-fmt.rs b/tests/ui/macros/assert-macro-fmt.rs
index 47554430379..3fd0f472d16 100644
--- a/tests/ui/macros/assert-macro-fmt.rs
+++ b/tests/ui/macros/assert-macro-fmt.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern: panicked
 //@ error-pattern: test-assert-fmt 42 rust
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     assert!(false, "test-assert-fmt {} {}", 42, "rust");
diff --git a/tests/ui/macros/assert-macro-owned.rs b/tests/ui/macros/assert-macro-owned.rs
index 46a59db1390..f9b6f5f5180 100644
--- a/tests/ui/macros/assert-macro-owned.rs
+++ b/tests/ui/macros/assert-macro-owned.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:panicked
 //@ error-pattern:test-assert-owned
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #![allow(non_fmt_panics)]
 
diff --git a/tests/ui/macros/assert-macro-static.rs b/tests/ui/macros/assert-macro-static.rs
index 7d9e345d516..8c91d7722fc 100644
--- a/tests/ui/macros/assert-macro-static.rs
+++ b/tests/ui/macros/assert-macro-static.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:panicked
 //@ error-pattern:test-assert-static
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     assert!(false, "test-assert-static");
diff --git a/tests/ui/macros/assert-matches-macro-msg.rs b/tests/ui/macros/assert-matches-macro-msg.rs
index efa4121da92..956bc9cf0f4 100644
--- a/tests/ui/macros/assert-matches-macro-msg.rs
+++ b/tests/ui/macros/assert-matches-macro-msg.rs
@@ -2,7 +2,7 @@
 //@ error-pattern:assertion `left matches right` failed: 1 + 1 definitely should be 3
 //@ error-pattern:  left: 2
 //@ error-pattern: right: 3
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #![feature(assert_matches)]
 
diff --git a/tests/ui/macros/assert-ne-macro-msg.rs b/tests/ui/macros/assert-ne-macro-msg.rs
index 0a578e1baf9..24bc4dbea47 100644
--- a/tests/ui/macros/assert-ne-macro-msg.rs
+++ b/tests/ui/macros/assert-ne-macro-msg.rs
@@ -2,7 +2,7 @@
 //@ error-pattern:assertion `left != right` failed: 1 + 1 definitely should not be 2
 //@ error-pattern:  left: 2
 //@ error-pattern: right: 2
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     assert_ne!(1 + 1, 2, "1 + 1 definitely should not be 2");
diff --git a/tests/ui/macros/assert-ne-macro-panic.rs b/tests/ui/macros/assert-ne-macro-panic.rs
index 9cf5f05e9f1..c349825baf3 100644
--- a/tests/ui/macros/assert-ne-macro-panic.rs
+++ b/tests/ui/macros/assert-ne-macro-panic.rs
@@ -2,7 +2,7 @@
 //@ error-pattern:assertion `left != right` failed
 //@ error-pattern:  left: 14
 //@ error-pattern: right: 14
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     assert_ne!(14, 14);
diff --git a/tests/ui/macros/die-macro-2.rs b/tests/ui/macros/die-macro-2.rs
index e5456bdfca0..d802f189ce1 100644
--- a/tests/ui/macros/die-macro-2.rs
+++ b/tests/ui/macros/die-macro-2.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:test
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     panic!("test");
diff --git a/tests/ui/macros/die-macro-expr.rs b/tests/ui/macros/die-macro-expr.rs
index fb92dd66e3d..f4fefb0ca37 100644
--- a/tests/ui/macros/die-macro-expr.rs
+++ b/tests/ui/macros/die-macro-expr.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:test
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     let __isize: isize = panic!("test");
diff --git a/tests/ui/macros/die-macro-pure.rs b/tests/ui/macros/die-macro-pure.rs
index 484eed3d720..d84787705a1 100644
--- a/tests/ui/macros/die-macro-pure.rs
+++ b/tests/ui/macros/die-macro-pure.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:test
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn f() {
     panic!("test");
diff --git a/tests/ui/macros/macro-span-issue-116502.stderr b/tests/ui/macros/macro-span-issue-116502.stderr
index da02855660a..2a581f7031b 100644
--- a/tests/ui/macros/macro-span-issue-116502.stderr
+++ b/tests/ui/macros/macro-span-issue-116502.stderr
@@ -17,13 +17,6 @@ LL |         T: Trait<m!()>;
    |                  ---- in this macro invocation
    |
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: use type parameters instead
-   |
-LL ~             U
-LL |         };
-LL |     }
-LL ~     struct S<U>(m!(), T)
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/macros/unimplemented-macro-panic.rs b/tests/ui/macros/unimplemented-macro-panic.rs
index d3bff8ca10b..804bd61270e 100644
--- a/tests/ui/macros/unimplemented-macro-panic.rs
+++ b/tests/ui/macros/unimplemented-macro-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:not implemented
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     unimplemented!()
diff --git a/tests/ui/macros/unreachable-arg.rs b/tests/ui/macros/unreachable-arg.rs
index 1f0d0073486..702bd053ab0 100644
--- a/tests/ui/macros/unreachable-arg.rs
+++ b/tests/ui/macros/unreachable-arg.rs
@@ -1,4 +1,4 @@
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 //@ revisions: edition_2015 edition_2021
 //@ [edition_2015]edition:2015
diff --git a/tests/ui/macros/unreachable-fmt-msg.rs b/tests/ui/macros/unreachable-fmt-msg.rs
index b16394a1920..928e0a427ae 100644
--- a/tests/ui/macros/unreachable-fmt-msg.rs
+++ b/tests/ui/macros/unreachable-fmt-msg.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:internal error: entered unreachable code: 6 is not prime
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     unreachable!("{} is not {}", 6u32, "prime");
diff --git a/tests/ui/macros/unreachable-format-arg.rs b/tests/ui/macros/unreachable-format-arg.rs
index 449c6bca16b..e1fdab25a43 100644
--- a/tests/ui/macros/unreachable-format-arg.rs
+++ b/tests/ui/macros/unreachable-format-arg.rs
@@ -1,5 +1,5 @@
 //@ run-fail
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 //@ revisions: edition_2015 edition_2021
 //@ [edition_2015]edition:2015
diff --git a/tests/ui/macros/unreachable-format-args.rs b/tests/ui/macros/unreachable-format-args.rs
index 5f8a0e9cdff..856fc992685 100644
--- a/tests/ui/macros/unreachable-format-args.rs
+++ b/tests/ui/macros/unreachable-format-args.rs
@@ -1,4 +1,4 @@
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 //@ revisions: edition_2015 edition_2021
 //@ [edition_2015]edition:2015
diff --git a/tests/ui/macros/unreachable-macro-panic.rs b/tests/ui/macros/unreachable-macro-panic.rs
index 7909bcb7624..c5cea5551cf 100644
--- a/tests/ui/macros/unreachable-macro-panic.rs
+++ b/tests/ui/macros/unreachable-macro-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:internal error: entered unreachable code
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     unreachable!()
diff --git a/tests/ui/macros/unreachable-static-msg.rs b/tests/ui/macros/unreachable-static-msg.rs
index 3e917897da4..a85f8962e7d 100644
--- a/tests/ui/macros/unreachable-static-msg.rs
+++ b/tests/ui/macros/unreachable-static-msg.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:internal error: entered unreachable code: uhoh
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     unreachable!("uhoh")
diff --git a/tests/ui/macros/unreachable.rs b/tests/ui/macros/unreachable.rs
index 7909bcb7624..c5cea5551cf 100644
--- a/tests/ui/macros/unreachable.rs
+++ b/tests/ui/macros/unreachable.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:internal error: entered unreachable code
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     unreachable!()
diff --git a/tests/ui/match/expr-match-panic-fn.rs b/tests/ui/match/expr-match-panic-fn.rs
index 82991d20df8..a07c2c6af8f 100644
--- a/tests/ui/match/expr-match-panic-fn.rs
+++ b/tests/ui/match/expr-match-panic-fn.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn f() -> ! {
     panic!()
diff --git a/tests/ui/match/expr-match-panic.rs b/tests/ui/match/expr-match-panic.rs
index e332ba83b91..d15b0a9cd72 100644
--- a/tests/ui/match/expr-match-panic.rs
+++ b/tests/ui/match/expr-match-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     let _x = match true {
diff --git a/tests/ui/match/match-bot-panic.rs b/tests/ui/match/match-bot-panic.rs
index a155b5fb3f2..7ec07ae290d 100644
--- a/tests/ui/match/match-bot-panic.rs
+++ b/tests/ui/match/match-bot-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #![allow(unreachable_code)]
 #![allow(unused_variables)]
diff --git a/tests/ui/match/match-disc-bot.rs b/tests/ui/match/match-disc-bot.rs
index fdb98a0accb..d65dc5aea07 100644
--- a/tests/ui/match/match-disc-bot.rs
+++ b/tests/ui/match/match-disc-bot.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:quux
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn f() -> ! {
     panic!("quux")
diff --git a/tests/ui/match/match-wildcards.rs b/tests/ui/match/match-wildcards.rs
index 4fddee6666e..1cc81a7c415 100644
--- a/tests/ui/match/match-wildcards.rs
+++ b/tests/ui/match/match-wildcards.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:squirrelcupcake
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn cmp() -> isize {
     match (Some('a'), None::<char>) {
diff --git a/tests/ui/meta/revision-ok.rs b/tests/ui/meta/revision-ok.rs
index c1387f7d18e..430d3d0a239 100644
--- a/tests/ui/meta/revision-ok.rs
+++ b/tests/ui/meta/revision-ok.rs
@@ -5,7 +5,7 @@
 //@ revisions: foo bar
 //@[foo] error-pattern:foo
 //@[bar] error-pattern:bar
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #[cfg(foo)]
 fn die() {
diff --git a/tests/ui/mir/mir_codegen_calls_converging_drops.rs b/tests/ui/mir/mir_codegen_calls_converging_drops.rs
index 5c3c8b999b2..8a6d3926de2 100644
--- a/tests/ui/mir/mir_codegen_calls_converging_drops.rs
+++ b/tests/ui/mir/mir_codegen_calls_converging_drops.rs
@@ -2,7 +2,7 @@
 //@ error-pattern:converging_fn called
 //@ error-pattern:0 dropped
 //@ error-pattern:exit
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 struct Droppable(u8);
 impl Drop for Droppable {
diff --git a/tests/ui/mir/mir_codegen_calls_converging_drops_2.rs b/tests/ui/mir/mir_codegen_calls_converging_drops_2.rs
index e3cb9a96de0..e89fbc58a0d 100644
--- a/tests/ui/mir/mir_codegen_calls_converging_drops_2.rs
+++ b/tests/ui/mir/mir_codegen_calls_converging_drops_2.rs
@@ -2,7 +2,7 @@
 //@ error-pattern:complex called
 //@ error-pattern:dropped
 //@ error-pattern:exit
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 struct Droppable;
 impl Drop for Droppable {
diff --git a/tests/ui/mir/mir_codegen_calls_diverging.rs b/tests/ui/mir/mir_codegen_calls_diverging.rs
index c62527f01d3..ce2d7140b07 100644
--- a/tests/ui/mir/mir_codegen_calls_diverging.rs
+++ b/tests/ui/mir/mir_codegen_calls_diverging.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:diverging_fn called
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn diverging_fn() -> ! {
     panic!("diverging_fn called")
diff --git a/tests/ui/mir/mir_dynamic_drops_1.rs b/tests/ui/mir/mir_dynamic_drops_1.rs
index ffb8cc26100..0b0a3960574 100644
--- a/tests/ui/mir/mir_dynamic_drops_1.rs
+++ b/tests/ui/mir/mir_dynamic_drops_1.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:drop 1
 //@ error-pattern:drop 2
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 /// Structure which will not allow to be dropped twice.
 struct Droppable<'a>(&'a mut bool, u32);
diff --git a/tests/ui/mir/mir_dynamic_drops_2.rs b/tests/ui/mir/mir_dynamic_drops_2.rs
index dc71f414673..f625f19be26 100644
--- a/tests/ui/mir/mir_dynamic_drops_2.rs
+++ b/tests/ui/mir/mir_dynamic_drops_2.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:drop 1
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 /// Structure which will not allow to be dropped twice.
 struct Droppable<'a>(&'a mut bool, u32);
diff --git a/tests/ui/mir/mir_dynamic_drops_3.rs b/tests/ui/mir/mir_dynamic_drops_3.rs
index fe84502ef1d..2a8af4ce1fb 100644
--- a/tests/ui/mir/mir_dynamic_drops_3.rs
+++ b/tests/ui/mir/mir_dynamic_drops_3.rs
@@ -4,7 +4,7 @@
 //@ error-pattern:drop 3
 //@ error-pattern:drop 2
 //@ error-pattern:drop 1
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 /// Structure which will not allow to be dropped twice.
 struct Droppable<'a>(&'a mut bool, u32);
diff --git a/tests/ui/mir/mir_indexing_oob_1.rs b/tests/ui/mir/mir_indexing_oob_1.rs
index 3afc2f0b32e..936484b0c1e 100644
--- a/tests/ui/mir/mir_indexing_oob_1.rs
+++ b/tests/ui/mir/mir_indexing_oob_1.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:index out of bounds: the len is 5 but the index is 10
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 const C: [u32; 5] = [0; 5];
 
diff --git a/tests/ui/mir/mir_indexing_oob_2.rs b/tests/ui/mir/mir_indexing_oob_2.rs
index 6e7c1c83536..310a7f8f2b7 100644
--- a/tests/ui/mir/mir_indexing_oob_2.rs
+++ b/tests/ui/mir/mir_indexing_oob_2.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:index out of bounds: the len is 5 but the index is 10
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 const C: &'static [u8; 5] = b"hello";
 
diff --git a/tests/ui/mir/mir_indexing_oob_3.rs b/tests/ui/mir/mir_indexing_oob_3.rs
index 4012864c6ce..44b3a2c5a6d 100644
--- a/tests/ui/mir/mir_indexing_oob_3.rs
+++ b/tests/ui/mir/mir_indexing_oob_3.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:index out of bounds: the len is 5 but the index is 10
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 const C: &'static [u8; 5] = b"hello";
 
diff --git a/tests/ui/never_type/return-never-coerce.rs b/tests/ui/never_type/return-never-coerce.rs
index 559b7d0e985..14f07dfeb76 100644
--- a/tests/ui/never_type/return-never-coerce.rs
+++ b/tests/ui/never_type/return-never-coerce.rs
@@ -2,7 +2,7 @@
 
 //@ run-fail
 //@ error-pattern:aah!
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn call_another_fn<T, F: FnOnce() -> T>(f: F) -> T {
     f()
diff --git a/tests/ui/nll/issue-51345-2.rs b/tests/ui/nll/issue-51345-2.rs
index f2501fdbab4..39871d56a9a 100644
--- a/tests/ui/nll/issue-51345-2.rs
+++ b/tests/ui/nll/issue-51345-2.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:thread 'main' panicked
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     let mut vec = vec![];
diff --git a/tests/ui/numbers-arithmetic/divide-by-zero.rs b/tests/ui/numbers-arithmetic/divide-by-zero.rs
index 626daf9771d..a05abadf4bb 100644
--- a/tests/ui/numbers-arithmetic/divide-by-zero.rs
+++ b/tests/ui/numbers-arithmetic/divide-by-zero.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:attempt to divide by zero
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #[allow(unconditional_panic)]
 fn main() {
diff --git a/tests/ui/numbers-arithmetic/int-abs-overflow.rs b/tests/ui/numbers-arithmetic/int-abs-overflow.rs
index e9114138048..6397f62d065 100644
--- a/tests/ui/numbers-arithmetic/int-abs-overflow.rs
+++ b/tests/ui/numbers-arithmetic/int-abs-overflow.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ compile-flags: -C overflow-checks=on
-//@ ignore-emscripten no threads support
+//@ needs-threads
 //@ needs-unwind
 
 use std::thread;
diff --git a/tests/ui/numbers-arithmetic/issue-8460.rs b/tests/ui/numbers-arithmetic/issue-8460.rs
index 9d3044a7ca0..87867fdc93e 100644
--- a/tests/ui/numbers-arithmetic/issue-8460.rs
+++ b/tests/ui/numbers-arithmetic/issue-8460.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 #![allow(unused_must_use)]
-//@ ignore-emscripten no threads support
+//@ needs-threads
 //@ needs-unwind
 #![feature(rustc_attrs)]
 
diff --git a/tests/ui/numbers-arithmetic/mod-zero.rs b/tests/ui/numbers-arithmetic/mod-zero.rs
index f3cc7c9fc88..300bd765c40 100644
--- a/tests/ui/numbers-arithmetic/mod-zero.rs
+++ b/tests/ui/numbers-arithmetic/mod-zero.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:attempt to calculate the remainder with a divisor of zero
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #[allow(unconditional_panic)]
 fn main() {
diff --git a/tests/ui/numbers-arithmetic/overflowing-add.rs b/tests/ui/numbers-arithmetic/overflowing-add.rs
index 16583f6eb74..c1f498c802b 100644
--- a/tests/ui/numbers-arithmetic/overflowing-add.rs
+++ b/tests/ui/numbers-arithmetic/overflowing-add.rs
@@ -2,7 +2,7 @@
 //@ error-pattern:thread 'main' panicked
 //@ error-pattern:attempt to add with overflow
 //@ compile-flags: -C debug-assertions
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #![allow(arithmetic_overflow)]
 
diff --git a/tests/ui/numbers-arithmetic/overflowing-mul.rs b/tests/ui/numbers-arithmetic/overflowing-mul.rs
index 59575d2e86e..0eece536929 100644
--- a/tests/ui/numbers-arithmetic/overflowing-mul.rs
+++ b/tests/ui/numbers-arithmetic/overflowing-mul.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:thread 'main' panicked
 //@ error-pattern:attempt to multiply with overflow
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 //@ compile-flags: -C debug-assertions
 
 #![allow(arithmetic_overflow)]
diff --git a/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs b/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs
index 8aa0d04e500..c5059c002b4 100644
--- a/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs
+++ b/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:attempt to negate with overflow
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 //@ compile-flags: -C debug-assertions
 #![allow(arithmetic_overflow)]
 
diff --git a/tests/ui/numbers-arithmetic/overflowing-pow-signed.rs b/tests/ui/numbers-arithmetic/overflowing-pow-signed.rs
index 69e22c2262a..28deb7cf6ba 100644
--- a/tests/ui/numbers-arithmetic/overflowing-pow-signed.rs
+++ b/tests/ui/numbers-arithmetic/overflowing-pow-signed.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:thread 'main' panicked
 //@ error-pattern:attempt to multiply with overflow
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 //@ compile-flags: -C debug-assertions
 
 fn main() {
diff --git a/tests/ui/numbers-arithmetic/overflowing-pow-unsigned.rs b/tests/ui/numbers-arithmetic/overflowing-pow-unsigned.rs
index f980033c480..dea9a4d5428 100644
--- a/tests/ui/numbers-arithmetic/overflowing-pow-unsigned.rs
+++ b/tests/ui/numbers-arithmetic/overflowing-pow-unsigned.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:thread 'main' panicked
 //@ error-pattern:attempt to multiply with overflow
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 //@ compile-flags: -C debug-assertions
 
 fn main() {
diff --git a/tests/ui/numbers-arithmetic/overflowing-sub.rs b/tests/ui/numbers-arithmetic/overflowing-sub.rs
index 44aadf6b3e7..88b1b693f63 100644
--- a/tests/ui/numbers-arithmetic/overflowing-sub.rs
+++ b/tests/ui/numbers-arithmetic/overflowing-sub.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:thread 'main' panicked
 //@ error-pattern:attempt to subtract with overflow
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 //@ compile-flags: -C debug-assertions
 
 #![allow(arithmetic_overflow)]
diff --git a/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs b/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs
index ce6644e6758..0566d2319df 100644
--- a/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs
+++ b/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs
@@ -1,10 +1,8 @@
 //@ run-pass
-#![allow(unused_variables)]
 //@ compile-flags:-C panic=abort
 //@ aux-build:exit-success-if-unwind.rs
 //@ no-prefer-dynamic
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 extern crate exit_success_if_unwind;
 
@@ -13,7 +11,7 @@ use std::process::Command;
 
 fn main() {
     let mut args = env::args_os();
-    let me = args.next().unwrap();
+    let _ = args.next().unwrap();
 
     if let Some(s) = args.next() {
         if &*s == "foo" {
diff --git a/tests/ui/panic-runtime/abort.rs b/tests/ui/panic-runtime/abort.rs
index caf0243ebdb..8cdfd018a92 100644
--- a/tests/ui/panic-runtime/abort.rs
+++ b/tests/ui/panic-runtime/abort.rs
@@ -1,9 +1,7 @@
 //@ run-pass
-#![allow(unused_variables)]
 //@ compile-flags:-C panic=abort
 //@ no-prefer-dynamic
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::env;
 use std::process::Command;
@@ -18,7 +16,7 @@ impl Drop for Bomb {
 
 fn main() {
     let mut args = env::args_os();
-    let me = args.next().unwrap();
+    let _ = args.next().unwrap();
 
     if let Some(s) = args.next() {
         if &*s == "foo" {
diff --git a/tests/ui/panic-runtime/lto-abort.rs b/tests/ui/panic-runtime/lto-abort.rs
index c66b6a60c73..cf15ae6435b 100644
--- a/tests/ui/panic-runtime/lto-abort.rs
+++ b/tests/ui/panic-runtime/lto-abort.rs
@@ -1,9 +1,7 @@
 //@ run-pass
-#![allow(unused_variables)]
 //@ compile-flags:-C lto -C panic=abort
 //@ no-prefer-dynamic
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::process::Command;
 use std::env;
@@ -18,7 +16,7 @@ impl Drop for Bomb {
 
 fn main() {
     let mut args = env::args_os();
-    let me = args.next().unwrap();
+    let _ = args.next().unwrap();
 
     if let Some(s) = args.next() {
         if &*s == "foo" {
diff --git a/tests/ui/panic-runtime/lto-unwind.rs b/tests/ui/panic-runtime/lto-unwind.rs
index 5eab2bd56ed..93275052f85 100644
--- a/tests/ui/panic-runtime/lto-unwind.rs
+++ b/tests/ui/panic-runtime/lto-unwind.rs
@@ -1,11 +1,8 @@
 //@ run-pass
-#![allow(unused_variables)]
-
 //@ compile-flags:-C lto -C panic=unwind
 //@ needs-unwind
 //@ no-prefer-dynamic
-//@ ignore-emscripten no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::process::Command;
 use std::env;
@@ -20,7 +17,7 @@ impl Drop for Bomb {
 
 fn main() {
     let mut args = env::args_os();
-    let me = args.next().unwrap();
+    let _ = args.next().unwrap();
 
     if let Some(s) = args.next() {
         if &*s == "foo" {
diff --git a/tests/ui/panic-runtime/unwind-interleaved.rs b/tests/ui/panic-runtime/unwind-interleaved.rs
index e5505cd893a..83eb6365097 100644
--- a/tests/ui/panic-runtime/unwind-interleaved.rs
+++ b/tests/ui/panic-runtime/unwind-interleaved.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn a() {}
 
diff --git a/tests/ui/panic-runtime/unwind-rec.rs b/tests/ui/panic-runtime/unwind-rec.rs
index d4b53c88768..a855a4de280 100644
--- a/tests/ui/panic-runtime/unwind-rec.rs
+++ b/tests/ui/panic-runtime/unwind-rec.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn build() -> Vec<isize> {
     panic!();
diff --git a/tests/ui/panic-runtime/unwind-rec2.rs b/tests/ui/panic-runtime/unwind-rec2.rs
index 6ac9a5a5805..ed02b117fff 100644
--- a/tests/ui/panic-runtime/unwind-rec2.rs
+++ b/tests/ui/panic-runtime/unwind-rec2.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn build1() -> Vec<isize> {
     vec![0, 0, 0, 0, 0, 0, 0]
diff --git a/tests/ui/panic-runtime/unwind-unique.rs b/tests/ui/panic-runtime/unwind-unique.rs
index a6cd59690ca..b57d81842c4 100644
--- a/tests/ui/panic-runtime/unwind-unique.rs
+++ b/tests/ui/panic-runtime/unwind-unique.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn failfn() {
     panic!();
diff --git a/tests/ui/panics/abort-on-panic.rs b/tests/ui/panics/abort-on-panic.rs
index feccefb2537..d3bf087bd3e 100644
--- a/tests/ui/panics/abort-on-panic.rs
+++ b/tests/ui/panics/abort-on-panic.rs
@@ -8,8 +8,7 @@
 // Since we mark some ABIs as "nounwind" to LLVM, we must make sure that
 // we never unwind through them.
 
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::io;
 use std::io::prelude::*;
diff --git a/tests/ui/panics/args-panic.rs b/tests/ui/panics/args-panic.rs
index 091ced9b479..9675c99dcb6 100644
--- a/tests/ui/panics/args-panic.rs
+++ b/tests/ui/panics/args-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:meep
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn f(_a: isize, _b: isize, _c: Box<isize>) {
     panic!("moop");
diff --git a/tests/ui/panics/doublepanic.rs b/tests/ui/panics/doublepanic.rs
index 51945ea708c..6fddde82a27 100644
--- a/tests/ui/panics/doublepanic.rs
+++ b/tests/ui/panics/doublepanic.rs
@@ -2,7 +2,7 @@
 
 //@ run-fail
 //@ error-pattern:One
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     panic!("One");
diff --git a/tests/ui/panics/explicit-panic-msg.rs b/tests/ui/panics/explicit-panic-msg.rs
index ef0c5b39f09..e5728ef1e20 100644
--- a/tests/ui/panics/explicit-panic-msg.rs
+++ b/tests/ui/panics/explicit-panic-msg.rs
@@ -4,7 +4,7 @@
 
 //@ run-fail
 //@ error-pattern:wooooo
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     let mut a = 1;
diff --git a/tests/ui/panics/explicit-panic.rs b/tests/ui/panics/explicit-panic.rs
index 34e952ef68f..7c69289940e 100644
--- a/tests/ui/panics/explicit-panic.rs
+++ b/tests/ui/panics/explicit-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:explicit
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     panic!();
diff --git a/tests/ui/panics/fmt-panic.rs b/tests/ui/panics/fmt-panic.rs
index 032f65cb2e4..c6cb039684d 100644
--- a/tests/ui/panics/fmt-panic.rs
+++ b/tests/ui/panics/fmt-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:meh
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     let str_var: String = "meh".to_string();
diff --git a/tests/ui/panics/issue-47429-short-backtraces.rs b/tests/ui/panics/issue-47429-short-backtraces.rs
index dff885af1b8..4a73ebe8712 100644
--- a/tests/ui/panics/issue-47429-short-backtraces.rs
+++ b/tests/ui/panics/issue-47429-short-backtraces.rs
@@ -17,10 +17,10 @@
 //@ ignore-msvc see #62897 and `backtrace-debuginfo.rs` test
 //@ ignore-android FIXME #17520
 //@ ignore-openbsd no support for libbacktrace without filename
-//@ ignore-wasm no panic or subprocess support
-//@ ignore-emscripten no panic or subprocess support
-//@ ignore-sgx no subprocess support
+//@ ignore-wasm no panic support
+//@ ignore-emscripten no panic support
 //@ ignore-fuchsia Backtraces not symbolized
+//@ needs-subprocess
 
 fn main() {
     panic!()
diff --git a/tests/ui/panics/main-panic.rs b/tests/ui/panics/main-panic.rs
index b69f1656ca4..0b3d5c3aaec 100644
--- a/tests/ui/panics/main-panic.rs
+++ b/tests/ui/panics/main-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:thread 'main' panicked at
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     panic!()
diff --git a/tests/ui/panics/panic-arg.rs b/tests/ui/panics/panic-arg.rs
index 10be6d5ff6c..037cfda3689 100644
--- a/tests/ui/panics/panic-arg.rs
+++ b/tests/ui/panics/panic-arg.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:woe
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn f(a: isize) {
     println!("{}", a);
diff --git a/tests/ui/panics/panic-handler-chain-update-hook.rs b/tests/ui/panics/panic-handler-chain-update-hook.rs
index 1f8fe30cfd8..662ea9e978f 100644
--- a/tests/ui/panics/panic-handler-chain-update-hook.rs
+++ b/tests/ui/panics/panic-handler-chain-update-hook.rs
@@ -2,7 +2,7 @@
 //@ needs-unwind
 #![allow(stable_features)]
 
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 #![feature(std_panic)]
 #![feature(panic_update_hook)]
diff --git a/tests/ui/panics/panic-handler-flail-wildly.rs b/tests/ui/panics/panic-handler-flail-wildly.rs
index 768c9d4c4c5..d42dfd68d9c 100644
--- a/tests/ui/panics/panic-handler-flail-wildly.rs
+++ b/tests/ui/panics/panic-handler-flail-wildly.rs
@@ -4,7 +4,7 @@
 #![allow(stable_features)]
 #![allow(unused_must_use)]
 
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 #![feature(std_panic)]
 
diff --git a/tests/ui/panics/panic-handler-set-twice.rs b/tests/ui/panics/panic-handler-set-twice.rs
index 902e48b6541..5f670d5f492 100644
--- a/tests/ui/panics/panic-handler-set-twice.rs
+++ b/tests/ui/panics/panic-handler-set-twice.rs
@@ -5,7 +5,7 @@
 
 #![feature(std_panic)]
 
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::panic;
diff --git a/tests/ui/panics/panic-in-dtor-drops-fields.rs b/tests/ui/panics/panic-in-dtor-drops-fields.rs
index 4d18dc0e059..38eb6d0acfb 100644
--- a/tests/ui/panics/panic-in-dtor-drops-fields.rs
+++ b/tests/ui/panics/panic-in-dtor-drops-fields.rs
@@ -3,7 +3,7 @@
 #![allow(dead_code)]
 #![allow(non_upper_case_globals)]
 
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 use std::thread;
 
diff --git a/tests/ui/panics/panic-macro-any-wrapped.rs b/tests/ui/panics/panic-macro-any-wrapped.rs
index 7c6790e35fd..e3a2dc6eed4 100644
--- a/tests/ui/panics/panic-macro-any-wrapped.rs
+++ b/tests/ui/panics/panic-macro-any-wrapped.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:panicked
 //@ error-pattern:Box<dyn Any>
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #![allow(non_fmt_panics)]
 
diff --git a/tests/ui/panics/panic-macro-any.rs b/tests/ui/panics/panic-macro-any.rs
index 75397333fa4..1392929b65c 100644
--- a/tests/ui/panics/panic-macro-any.rs
+++ b/tests/ui/panics/panic-macro-any.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:panicked
 //@ error-pattern:Box<dyn Any>
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #![allow(non_fmt_panics)]
 
diff --git a/tests/ui/panics/panic-macro-explicit.rs b/tests/ui/panics/panic-macro-explicit.rs
index 2c7b84d99fe..b9195e3b0fc 100644
--- a/tests/ui/panics/panic-macro-explicit.rs
+++ b/tests/ui/panics/panic-macro-explicit.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:panicked
 //@ error-pattern:explicit panic
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     panic!();
diff --git a/tests/ui/panics/panic-macro-fmt.rs b/tests/ui/panics/panic-macro-fmt.rs
index 1a63a06c75a..550cd5c1ee3 100644
--- a/tests/ui/panics/panic-macro-fmt.rs
+++ b/tests/ui/panics/panic-macro-fmt.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:panicked
 //@ error-pattern:test-fail-fmt 42 rust
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     panic!("test-fail-fmt {} {}", 42, "rust");
diff --git a/tests/ui/panics/panic-macro-owned.rs b/tests/ui/panics/panic-macro-owned.rs
index 1878f3d52ab..4df04c50bc3 100644
--- a/tests/ui/panics/panic-macro-owned.rs
+++ b/tests/ui/panics/panic-macro-owned.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:panicked
 //@ error-pattern:test-fail-owned
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     panic!("test-fail-owned");
diff --git a/tests/ui/panics/panic-macro-static.rs b/tests/ui/panics/panic-macro-static.rs
index 018166e60cf..1c6258ebed2 100644
--- a/tests/ui/panics/panic-macro-static.rs
+++ b/tests/ui/panics/panic-macro-static.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:panicked
 //@ error-pattern:test-fail-static
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     panic!("test-fail-static");
diff --git a/tests/ui/panics/panic-main.rs b/tests/ui/panics/panic-main.rs
index d71fca0754e..3876dbb37c3 100644
--- a/tests/ui/panics/panic-main.rs
+++ b/tests/ui/panics/panic-main.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:moop
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     panic!("moop");
diff --git a/tests/ui/panics/panic-parens.rs b/tests/ui/panics/panic-parens.rs
index 271d0363cab..5440bf18f25 100644
--- a/tests/ui/panics/panic-parens.rs
+++ b/tests/ui/panics/panic-parens.rs
@@ -3,7 +3,7 @@
 
 //@ run-fail
 //@ error-pattern:oops
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn bigpanic() {
     while (panic!("oops")) {
diff --git a/tests/ui/panics/panic-recover-propagate.rs b/tests/ui/panics/panic-recover-propagate.rs
index f8be86be19d..ef6ae4fd788 100644
--- a/tests/ui/panics/panic-recover-propagate.rs
+++ b/tests/ui/panics/panic-recover-propagate.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ needs-unwind
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::panic;
diff --git a/tests/ui/panics/panic-set-handler.rs b/tests/ui/panics/panic-set-handler.rs
index 39286ca865b..41e513e0bd6 100644
--- a/tests/ui/panics/panic-set-handler.rs
+++ b/tests/ui/panics/panic-set-handler.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:greetings from the panic handler
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 use std::panic;
 
diff --git a/tests/ui/panics/panic-set-unset-handler.rs b/tests/ui/panics/panic-set-unset-handler.rs
index 02f1599338b..66d5003d0f1 100644
--- a/tests/ui/panics/panic-set-unset-handler.rs
+++ b/tests/ui/panics/panic-set-unset-handler.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:thread 'main' panicked
 //@ error-pattern:foobar
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 use std::panic;
 
diff --git a/tests/ui/panics/panic-take-handler-nop.rs b/tests/ui/panics/panic-take-handler-nop.rs
index 89e1d234df1..f10582872df 100644
--- a/tests/ui/panics/panic-take-handler-nop.rs
+++ b/tests/ui/panics/panic-take-handler-nop.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:thread 'main' panicked
 //@ error-pattern:foobar
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 use std::panic;
 
diff --git a/tests/ui/panics/panic.rs b/tests/ui/panics/panic.rs
index b9721ac8230..068f187524d 100644
--- a/tests/ui/panics/panic.rs
+++ b/tests/ui/panics/panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:1 == 2
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     assert!(1 == 2);
diff --git a/tests/ui/panics/result-get-panic.rs b/tests/ui/panics/result-get-panic.rs
index d7f6dfe8406..b8dc49f9aca 100644
--- a/tests/ui/panics/result-get-panic.rs
+++ b/tests/ui/panics/result-get-panic.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:called `Result::unwrap()` on an `Err` value
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 use std::result::Result::Err;
 
diff --git a/tests/ui/panics/runtime-switch.rs b/tests/ui/panics/runtime-switch.rs
index ffd038f9535..9f0be8c7ddf 100644
--- a/tests/ui/panics/runtime-switch.rs
+++ b/tests/ui/panics/runtime-switch.rs
@@ -18,9 +18,9 @@
 //@ ignore-android FIXME #17520
 //@ ignore-openbsd no support for libbacktrace without filename
 //@ ignore-wasm no backtrace support
-//@ ignore-emscripten no panic or subprocess support
-//@ ignore-sgx no subprocess support
+//@ ignore-emscripten no panic support
 //@ ignore-fuchsia Backtrace not symbolized
+//@ needs-subprocess
 
 #![feature(panic_backtrace_config)]
 
diff --git a/tests/ui/panics/test-panic.rs b/tests/ui/panics/test-panic.rs
index 29a3c4e9c9f..c7af47524cf 100644
--- a/tests/ui/panics/test-panic.rs
+++ b/tests/ui/panics/test-panic.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ check-stdout
 //@ compile-flags: --test
-//@ ignore-emscripten
+//@ needs-subprocess
 
 #[test]
 fn test_foo() {
diff --git a/tests/ui/panics/test-should-panic-no-message.rs b/tests/ui/panics/test-should-panic-no-message.rs
index b6ed6b19dd0..05fc927d876 100644
--- a/tests/ui/panics/test-should-panic-no-message.rs
+++ b/tests/ui/panics/test-should-panic-no-message.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ compile-flags: --test
 //@ check-stdout
-//@ ignore-wasm32 no processes
+//@ needs-subprocess
 
 #[test]
 #[should_panic(expected = "foo")]
diff --git a/tests/ui/panics/while-body-panics.rs b/tests/ui/panics/while-body-panics.rs
index bddcd5d50ce..8459a8d63bf 100644
--- a/tests/ui/panics/while-body-panics.rs
+++ b/tests/ui/panics/while-body-panics.rs
@@ -2,7 +2,7 @@
 
 //@ run-fail
 //@ error-pattern:quux
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     let _x: isize = {
diff --git a/tests/ui/panics/while-panic.rs b/tests/ui/panics/while-panic.rs
index 2961e8599c3..4c8431c71d1 100644
--- a/tests/ui/panics/while-panic.rs
+++ b/tests/ui/panics/while-panic.rs
@@ -2,7 +2,7 @@
 
 //@ run-fail
 //@ error-pattern:giraffe
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     panic!("{}", {
diff --git a/tests/ui/parser/issues/issue-14303-fncall.full.stderr b/tests/ui/parser/issues/issue-14303-fncall.full.stderr
index 1986f70bf67..5a017c85c16 100644
--- a/tests/ui/parser/issues/issue-14303-fncall.full.stderr
+++ b/tests/ui/parser/issues/issue-14303-fncall.full.stderr
@@ -1,8 +1,8 @@
-error[E0747]: type provided when a lifetime was expected
-  --> $DIR/issue-14303-fncall.rs:15:26
+error[E0747]: placeholder provided when a lifetime was expected
+  --> $DIR/issue-14303-fncall.rs:12:77
    |
-LL |         .collect::<Vec<S<_, 'a>>>();
-   |                          ^
+LL |     let _x = (*start..*end).map(|x| S { a: start, b: end }).collect::<Vec<S<_, 'a>>>();
+   |                                                                             ^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-14303-fncall.generic_arg.stderr b/tests/ui/parser/issues/issue-14303-fncall.generic_arg.stderr
index 2de59b8c746..5a017c85c16 100644
--- a/tests/ui/parser/issues/issue-14303-fncall.generic_arg.stderr
+++ b/tests/ui/parser/issues/issue-14303-fncall.generic_arg.stderr
@@ -1,8 +1,8 @@
-error[E0747]: inferred provided when a lifetime was expected
-  --> $DIR/issue-14303-fncall.rs:15:26
+error[E0747]: placeholder provided when a lifetime was expected
+  --> $DIR/issue-14303-fncall.rs:12:77
    |
-LL |         .collect::<Vec<S<_, 'a>>>();
-   |                          ^
+LL |     let _x = (*start..*end).map(|x| S { a: start, b: end }).collect::<Vec<S<_, 'a>>>();
+   |                                                                             ^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-14303-fncall.rs b/tests/ui/parser/issues/issue-14303-fncall.rs
index 59d4eab06d6..8f7fbec9470 100644
--- a/tests/ui/parser/issues/issue-14303-fncall.rs
+++ b/tests/ui/parser/issues/issue-14303-fncall.rs
@@ -3,18 +3,15 @@
 // we need the above to avoid ast borrowck failure in recovered code
 #![cfg_attr(generic_arg, feature(generic_arg_infer))]
 
-
 struct S<'a, T> {
     a: &'a T,
     b: &'a T,
 }
 
 fn foo<'a, 'b>(start: &'a usize, end: &'a usize) {
-    let _x = (*start..*end)
-        .map(|x| S { a: start, b: end })
-        .collect::<Vec<S<_, 'a>>>();
-        //[generic_arg]~^ ERROR inferred provided when a lifetime was expected
-        //[full]~^^ ERROR type provided when a lifetime was expected
+    let _x = (*start..*end).map(|x| S { a: start, b: end }).collect::<Vec<S<_, 'a>>>();
+    //[generic_arg]~^ ERROR placeholder provided when a lifetime was expected
+    //[full]~^^ ERROR placeholder provided when a lifetime was expected
 }
 
 fn main() {}
diff --git a/tests/ui/print-stdout-eprint-stderr.rs b/tests/ui/print-stdout-eprint-stderr.rs
index e84a9bebc49..4b356e2fe61 100644
--- a/tests/ui/print-stdout-eprint-stderr.rs
+++ b/tests/ui/print-stdout-eprint-stderr.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 spawning processes is not supported
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::{env, process};
 
diff --git a/tests/ui/process/core-run-destroy.rs b/tests/ui/process/core-run-destroy.rs
index 3f2ea0e8441..b4815c9dfbb 100644
--- a/tests/ui/process/core-run-destroy.rs
+++ b/tests/ui/process/core-run-destroy.rs
@@ -1,12 +1,11 @@
 //@ run-pass
 
 #![allow(unused_must_use)]
-#![allow(stable_features)]
 #![allow(deprecated)]
 #![allow(unused_imports)]
+
 //@ compile-flags:--test
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-vxworks no 'cat' and 'sleep'
 //@ ignore-fuchsia no 'cat'
 
diff --git a/tests/ui/process/env-args-reverse-iterator.rs b/tests/ui/process/env-args-reverse-iterator.rs
index 830e9535466..f0afeeb22eb 100644
--- a/tests/ui/process/env-args-reverse-iterator.rs
+++ b/tests/ui/process/env-args-reverse-iterator.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::env::args;
 use std::process::Command;
diff --git a/tests/ui/process/fds-are-cloexec.rs b/tests/ui/process/fds-are-cloexec.rs
index e7b000b2c49..f6678379dd6 100644
--- a/tests/ui/process/fds-are-cloexec.rs
+++ b/tests/ui/process/fds-are-cloexec.rs
@@ -1,9 +1,8 @@
 //@ run-pass
-//@ ignore-windows
+//@ only-unix
 //@ ignore-android
-//@ ignore-wasm32 no processes
+//@ needs-subprocess
 //@ ignore-haiku
-//@ ignore-sgx no processes
 
 #![feature(rustc_private)]
 
diff --git a/tests/ui/process/inherit-env.rs b/tests/ui/process/inherit-env.rs
index 0eb61fcdd53..09d5b76141e 100644
--- a/tests/ui/process/inherit-env.rs
+++ b/tests/ui/process/inherit-env.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no subprocess support
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::env;
 use std::process::Command;
diff --git a/tests/ui/process/issue-13304.rs b/tests/ui/process/issue-13304.rs
index 6dbf0caaaec..621c54300d3 100644
--- a/tests/ui/process/issue-13304.rs
+++ b/tests/ui/process/issue-13304.rs
@@ -1,7 +1,5 @@
 //@ run-pass
-#![allow(unused_mut)]
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::env;
 use std::io::prelude::*;
@@ -32,7 +30,7 @@ fn parent() {
 }
 
 fn child() {
-    let mut stdin = io::stdin();
+    let stdin = io::stdin();
     for line in stdin.lock().lines() {
         println!("{}", line.unwrap());
     }
diff --git a/tests/ui/process/issue-14456.rs b/tests/ui/process/issue-14456.rs
index fd6da8a5fc4..e67a9d8bad5 100644
--- a/tests/ui/process/issue-14456.rs
+++ b/tests/ui/process/issue-14456.rs
@@ -1,7 +1,5 @@
 //@ run-pass
-#![allow(unused_mut)]
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::env;
 use std::io::prelude::*;
@@ -20,7 +18,7 @@ fn main() {
 fn child() {
     writeln!(&mut io::stdout(), "foo").unwrap();
     writeln!(&mut io::stderr(), "bar").unwrap();
-    let mut stdin = io::stdin();
+    let stdin = io::stdin();
     let mut s = String::new();
     stdin.lock().read_line(&mut s).unwrap();
     assert_eq!(s.len(), 0);
diff --git a/tests/ui/process/issue-14940.rs b/tests/ui/process/issue-14940.rs
index 13fb18154a0..cfbc743250f 100644
--- a/tests/ui/process/issue-14940.rs
+++ b/tests/ui/process/issue-14940.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::env;
 use std::process::Command;
diff --git a/tests/ui/process/issue-16272.rs b/tests/ui/process/issue-16272.rs
index bf26769d494..72708554753 100644
--- a/tests/ui/process/issue-16272.rs
+++ b/tests/ui/process/issue-16272.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::process::Command;
 use std::env;
diff --git a/tests/ui/process/issue-20091.rs b/tests/ui/process/issue-20091.rs
index b6d94661b75..72bf4c0e71e 100644
--- a/tests/ui/process/issue-20091.rs
+++ b/tests/ui/process/issue-20091.rs
@@ -1,9 +1,5 @@
 //@ run-pass
-#![allow(stable_features)]
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
-
-#![feature(os)]
+//@ needs-subprocess
 
 #[cfg(unix)]
 fn main() {
diff --git a/tests/ui/process/issue-30490.rs b/tests/ui/process/issue-30490.rs
index 0d918bc3dd5..75b36e7c20b 100644
--- a/tests/ui/process/issue-30490.rs
+++ b/tests/ui/process/issue-30490.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-emscripten no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-fuchsia Child I/O swaps not privileged
 
 // Previously libstd would set stdio descriptors of a child process
diff --git a/tests/ui/process/multi-panic.rs b/tests/ui/process/multi-panic.rs
index ad47925a149..481fe75c731 100644
--- a/tests/ui/process/multi-panic.rs
+++ b/tests/ui/process/multi-panic.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ needs-unwind
 
 fn check_for_no_backtrace(test: std::process::Output) {
diff --git a/tests/ui/process/no-stdio.rs b/tests/ui/process/no-stdio.rs
index 8eebf6dbc7d..5cc7cacbb22 100644
--- a/tests/ui/process/no-stdio.rs
+++ b/tests/ui/process/no-stdio.rs
@@ -1,7 +1,6 @@
 //@ run-pass
 //@ ignore-android
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 #![feature(rustc_private)]
 
diff --git a/tests/ui/process/println-with-broken-pipe.rs b/tests/ui/process/println-with-broken-pipe.rs
index d88c6dcc12b..fbac9b6cd95 100644
--- a/tests/ui/process/println-with-broken-pipe.rs
+++ b/tests/ui/process/println-with-broken-pipe.rs
@@ -1,7 +1,7 @@
 //@ run-pass
 //@ check-run-results
+//@ needs-subprocess
 //@ ignore-windows
-//@ ignore-wasm32
 //@ ignore-fuchsia
 //@ ignore-horizon
 //@ ignore-android
diff --git a/tests/ui/process/process-envs.rs b/tests/ui/process/process-envs.rs
index 15285960d16..98052f1d3a5 100644
--- a/tests/ui/process/process-envs.rs
+++ b/tests/ui/process/process-envs.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-vxworks no 'env'
 //@ ignore-fuchsia no 'env'
 
diff --git a/tests/ui/process/process-exit.rs b/tests/ui/process/process-exit.rs
index a75a7306cbc..a1ed243b62b 100644
--- a/tests/ui/process/process-exit.rs
+++ b/tests/ui/process/process-exit.rs
@@ -1,10 +1,8 @@
 //@ run-pass
-#![allow(unused_imports)]
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::env;
-use std::process::{self, Command, Stdio};
+use std::process::{self, Command};
 
 fn main() {
     let args: Vec<String> = env::args().collect();
diff --git a/tests/ui/process/process-panic-after-fork.rs b/tests/ui/process/process-panic-after-fork.rs
index afb1b721182..6e0267e0a54 100644
--- a/tests/ui/process/process-panic-after-fork.rs
+++ b/tests/ui/process/process-panic-after-fork.rs
@@ -1,8 +1,7 @@
 //@ run-pass
 //@ no-prefer-dynamic
-//@ ignore-windows
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ only-unix
+//@ needs-subprocess
 //@ ignore-fuchsia no fork
 
 #![feature(rustc_private)]
diff --git a/tests/ui/process/process-remove-from-env.rs b/tests/ui/process/process-remove-from-env.rs
index 21fff4fd45d..c1a2b2daf5b 100644
--- a/tests/ui/process/process-remove-from-env.rs
+++ b/tests/ui/process/process-remove-from-env.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-vxworks no 'env'
 //@ ignore-fuchsia no 'env'
 
diff --git a/tests/ui/process/process-sigpipe.rs b/tests/ui/process/process-sigpipe.rs
index 9db130c26bd..453e53379fc 100644
--- a/tests/ui/process/process-sigpipe.rs
+++ b/tests/ui/process/process-sigpipe.rs
@@ -15,7 +15,7 @@
 
 //@ ignore-vxworks no 'sh'
 //@ ignore-fuchsia no 'sh'
-//@ ignore-emscripten No threads
+//@ needs-threads
 //@ only-unix SIGPIPE is a unix feature
 
 use std::process;
diff --git a/tests/ui/process/process-spawn-nonexistent.rs b/tests/ui/process/process-spawn-nonexistent.rs
index 1cd32866299..3db670624fb 100644
--- a/tests/ui/process/process-spawn-nonexistent.rs
+++ b/tests/ui/process/process-spawn-nonexistent.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-fuchsia ErrorKind not translated
 
 use std::io::ErrorKind;
diff --git a/tests/ui/process/process-spawn-with-unicode-params.rs b/tests/ui/process/process-spawn-with-unicode-params.rs
index 4d2ba49eeac..65f835c1345 100644
--- a/tests/ui/process/process-spawn-with-unicode-params.rs
+++ b/tests/ui/process/process-spawn-with-unicode-params.rs
@@ -7,8 +7,7 @@
 // non-ASCII characters.  The child process ensures all the strings are
 // intact.
 
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-fuchsia Filesystem manipulation privileged
 
 use std::io::prelude::*;
diff --git a/tests/ui/process/process-status-inherits-stdin.rs b/tests/ui/process/process-status-inherits-stdin.rs
index 39eef34c5f8..d5dd0e55fa3 100644
--- a/tests/ui/process/process-status-inherits-stdin.rs
+++ b/tests/ui/process/process-status-inherits-stdin.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::env;
 use std::io;
diff --git a/tests/ui/process/signal-exit-status.rs b/tests/ui/process/signal-exit-status.rs
index a6acea47636..33aa83abfc3 100644
--- a/tests/ui/process/signal-exit-status.rs
+++ b/tests/ui/process/signal-exit-status.rs
@@ -1,7 +1,6 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
-//@ ignore-windows
+//@ needs-subprocess
+//@ only-unix (`code()` returns `None` if terminated by a signal on Unix)
 //@ ignore-fuchsia code returned as ZX_TASK_RETCODE_EXCEPTION_KILL, FIXME (#58590)
 
 #![feature(core_intrinsics)]
diff --git a/tests/ui/process/sigpipe-should-be-ignored.rs b/tests/ui/process/sigpipe-should-be-ignored.rs
index 44785bee7f8..3dcf0117ae9 100644
--- a/tests/ui/process/sigpipe-should-be-ignored.rs
+++ b/tests/ui/process/sigpipe-should-be-ignored.rs
@@ -1,12 +1,9 @@
 //@ run-pass
+//@ needs-subprocess
 
-#![allow(unused_must_use)]
 // Be sure that when a SIGPIPE would have been received that the entire process
 // doesn't die in a ball of fire, but rather it's gracefully handled.
 
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
-
 use std::env;
 use std::io::prelude::*;
 use std::io;
@@ -14,7 +11,7 @@ use std::process::{Command, Stdio};
 
 fn test() {
     let _ = io::stdin().read_line(&mut String::new());
-    io::stdout().write(&[1]);
+    io::stdout().write(&[1]).unwrap();
     assert!(io::stdout().flush().is_err());
 }
 
diff --git a/tests/ui/process/tls-exit-status.rs b/tests/ui/process/tls-exit-status.rs
index cddcf369da0..6dd0d71ef35 100644
--- a/tests/ui/process/tls-exit-status.rs
+++ b/tests/ui/process/tls-exit-status.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:nonzero
 //@ exec-env:RUST_NEWRT=1
-//@ ignore-wasm32 no processes
+//@ needs-subprocess
 
 use std::env;
 
diff --git a/tests/ui/process/try-wait.rs b/tests/ui/process/try-wait.rs
index b6d026d802f..dcef43ad348 100644
--- a/tests/ui/process/try-wait.rs
+++ b/tests/ui/process/try-wait.rs
@@ -1,9 +1,5 @@
 //@ run-pass
-
-#![allow(stable_features)]
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
-#![feature(process_try_wait)]
+//@ needs-subprocess
 
 use std::env;
 use std::process::Command;
diff --git a/tests/ui/reachable/issue-948.rs b/tests/ui/reachable/issue-948.rs
index 8e239a1115e..6181e547acc 100644
--- a/tests/ui/reachable/issue-948.rs
+++ b/tests/ui/reachable/issue-948.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:beep boop
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #![allow(unused_variables)]
 
diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error-err.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error-err.rs
index fb6718e55b2..00a0ea04c0d 100644
--- a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error-err.rs
+++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error-err.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:returned Box<dyn Error> from main()
 //@ failure-status: 1
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 use std::error::Error;
 use std::io;
diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-never.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-never.rs
index 91be3afbe22..3b80c2b49a5 100644
--- a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-never.rs
+++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-never.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:oh, dear
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() -> ! {
     panic!("oh, dear");
diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs
index f1d972b3c55..48605309965 100644
--- a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs
+++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern:returned Box<Error> from main()
 //@ failure-status: 1
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 use std::io::{Error, ErrorKind};
 
diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str-err.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str-err.rs
index acf3da2d55f..8f7b3da31bb 100644
--- a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str-err.rs
+++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str-err.rs
@@ -1,7 +1,7 @@
 //@ run-fail
 //@ error-pattern: An error message for you
 //@ failure-status: 1
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() -> Result<(), &'static str> {
     Err("An error message for you")
diff --git a/tests/ui/runtime/atomic-print.rs b/tests/ui/runtime/atomic-print.rs
index 73520589736..6b899d675a2 100644
--- a/tests/ui/runtime/atomic-print.rs
+++ b/tests/ui/runtime/atomic-print.rs
@@ -2,8 +2,8 @@
 
 #![allow(unused_must_use)]
 #![allow(deprecated)]
-//@ ignore-wasm32 no processes or threads
-//@ ignore-sgx no processes
+//@ needs-threads
+//@ needs-subprocess
 
 use std::{env, fmt, process, sync, thread};
 
diff --git a/tests/ui/runtime/backtrace-debuginfo.rs b/tests/ui/runtime/backtrace-debuginfo.rs
index da747ded44f..afc96d6bb5f 100644
--- a/tests/ui/runtime/backtrace-debuginfo.rs
+++ b/tests/ui/runtime/backtrace-debuginfo.rs
@@ -9,8 +9,7 @@
 //@ compile-flags:-g -Copt-level=0 -Cllvm-args=-enable-tail-merge=0
 //@ compile-flags:-Cforce-frame-pointers=yes
 //@ compile-flags:-Cstrip=none
-//@ ignore-wasm32 spawning processes is not supported
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-fuchsia Backtrace not symbolized, trace different line alignment
 
 // FIXME(#117097): backtrace (possibly unwinding mechanism) seems to be different on at least
diff --git a/tests/ui/runtime/out-of-stack.rs b/tests/ui/runtime/out-of-stack.rs
index c5300635ad9..6be34afb560 100644
--- a/tests/ui/runtime/out-of-stack.rs
+++ b/tests/ui/runtime/out-of-stack.rs
@@ -3,8 +3,7 @@
 #![allow(unused_must_use)]
 #![allow(unconditional_recursion)]
 //@ ignore-android: FIXME (#20004)
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-fuchsia must translate zircon signal to SIGABRT, FIXME (#58590)
 //@ ignore-nto no stack overflow handler used (no alternate stack available)
 //@ ignore-ios stack overflow handlers aren't enabled
diff --git a/tests/ui/runtime/rt-explody-panic-payloads.rs b/tests/ui/runtime/rt-explody-panic-payloads.rs
index bd3624a8aee..c177fd260ed 100644
--- a/tests/ui/runtime/rt-explody-panic-payloads.rs
+++ b/tests/ui/runtime/rt-explody-panic-payloads.rs
@@ -1,7 +1,6 @@
 //@ run-pass
 //@ needs-unwind
-//@ ignore-emscripten no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::env;
 use std::process::Command;
diff --git a/tests/ui/runtime/running-with-no-runtime.rs b/tests/ui/runtime/running-with-no-runtime.rs
index 5c219b6feda..7ac0dd912dc 100644
--- a/tests/ui/runtime/running-with-no-runtime.rs
+++ b/tests/ui/runtime/running-with-no-runtime.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 spawning processes is not supported
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 #![no_main]
 
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr b/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr
index 9af2a08f371..bafa290a3cf 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr
@@ -53,7 +53,7 @@ LL |     assert_eq!(smart_ptr.a::<&Foo>(), 2);
    |                ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
    |
    = note: expected reference `&Foo`
-                 found struct `SmartPtr<'_, Foo, >`
+                 found struct `SmartPtr<'_, Foo>`
 
 error[E0308]: mismatched types
   --> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:62:16
@@ -62,7 +62,7 @@ LL |     assert_eq!(smart_ptr.b::<&Foo>(), 1);
    |                ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
    |
    = note: expected reference `&Foo`
-                 found struct `SmartPtr<'_, Foo, >`
+                 found struct `SmartPtr<'_, Foo>`
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr b/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr
index 6e864f44aa3..f67918a2577 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr
@@ -83,7 +83,7 @@ LL |     smart_ptr.get::<&Foo>();
    |     ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
    |
    = note: expected reference `&Foo`
-                 found struct `SmartPtr<'_, Foo, >`
+                 found struct `SmartPtr<'_, Foo>`
 
 error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
   --> $DIR/arbitrary-self-from-method-substs.rs:92:9
diff --git a/tests/ui/sepcomp/sepcomp-unwind.rs b/tests/ui/sepcomp/sepcomp-unwind.rs
index 6a40b5ccc12..8c25278bb7e 100644
--- a/tests/ui/sepcomp/sepcomp-unwind.rs
+++ b/tests/ui/sepcomp/sepcomp-unwind.rs
@@ -2,7 +2,7 @@
 //@ needs-unwind
 #![allow(dead_code)]
 //@ compile-flags: -C codegen-units=3
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 // Test unwinding through multiple compilation units.
 
diff --git a/tests/ui/simd/target-feature-mixup.rs b/tests/ui/simd/target-feature-mixup.rs
index 62d87c3a6dc..2786251c795 100644
--- a/tests/ui/simd/target-feature-mixup.rs
+++ b/tests/ui/simd/target-feature-mixup.rs
@@ -3,8 +3,7 @@
 #![allow(stable_features)]
 #![allow(overflowing_literals)]
 
-//@ ignore-wasm32 no subprocess support
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-fuchsia must translate zircon signal to SIGILL, FIXME (#58590)
 
 #![feature(repr_simd, target_feature, cfg_target_feature)]
diff --git a/tests/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr b/tests/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr
index a4b65256574..6559845c23e 100644
--- a/tests/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr
+++ b/tests/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr
@@ -17,10 +17,6 @@ error[E0282]: type annotations needed
 LL |         .sum::<_>()
    |          ^^^ cannot infer type of the type parameter `S` declared on the method `sum`
    |
-help: consider specifying the generic argument
-   |
-LL |         .sum::<S>()
-   |             ~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/std/thread-sleep-ms.rs b/tests/ui/std/thread-sleep-ms.rs
index 0a3d0253a20..2d668b8265c 100644
--- a/tests/ui/std/thread-sleep-ms.rs
+++ b/tests/ui/std/thread-sleep-ms.rs
@@ -1,12 +1,9 @@
 //@ run-pass
-//@ ignore-sgx not supported
-//@ ignore-emscripten
-// FIXME: test hangs on emscripten
-#![allow(deprecated)]
-#![allow(unused_imports)]
+//@ needs-threads
+//@ ignore-emscripten (FIXME: test hangs on emscripten)
 
-use std::thread;
+#![allow(deprecated)]
 
 fn main() {
-    thread::sleep_ms(250);
+    std::thread::sleep_ms(250);
 }
diff --git a/tests/ui/stdio-is-blocking.rs b/tests/ui/stdio-is-blocking.rs
index dda100951dd..615530dcd47 100644
--- a/tests/ui/stdio-is-blocking.rs
+++ b/tests/ui/stdio-is-blocking.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::env;
 use std::io::prelude::*;
diff --git a/tests/ui/str/str-overrun.rs b/tests/ui/str/str-overrun.rs
index b8e245475da..6d62b837694 100644
--- a/tests/ui/str/str-overrun.rs
+++ b/tests/ui/str/str-overrun.rs
@@ -1,6 +1,6 @@
 //@ run-fail
 //@ error-pattern:index out of bounds: the len is 5 but the index is 5
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 fn main() {
     let s: String = "hello".to_string();
diff --git a/tests/ui/structs-enums/unit-like-struct-drop-run.rs b/tests/ui/structs-enums/unit-like-struct-drop-run.rs
index 02d14265f3e..3d00871837c 100644
--- a/tests/ui/structs-enums/unit-like-struct-drop-run.rs
+++ b/tests/ui/structs-enums/unit-like-struct-drop-run.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ needs-unwind
-//@ ignore-emscripten no threads support
+//@ needs-threads
 
 // Make sure the destructor is run for unit-like structs.
 
diff --git a/tests/ui/structs/rhs-type.rs b/tests/ui/structs/rhs-type.rs
index fde5c16a068..8ce924672cf 100644
--- a/tests/ui/structs/rhs-type.rs
+++ b/tests/ui/structs/rhs-type.rs
@@ -3,7 +3,7 @@
 
 //@ run-fail
 //@ error-pattern:bye
-//@ ignore-emscripten no processes
+//@ needs-subprocess
 
 #![allow(unreachable_code)]
 #![allow(unused_variables)]
diff --git a/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs b/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs
new file mode 100644
index 00000000000..a9c2c20ef37
--- /dev/null
+++ b/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs
@@ -0,0 +1,51 @@
+// https://github.com/rust-lang/rust/issues/109195
+struct Foo;
+
+impl Foo {
+    fn bar_baz() {}
+}
+
+impl Foo {
+    fn bar_quux() {}
+}
+
+fn main() {
+    String::from::utf8;
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP there is an associated function with a similar name: `from_utf8`
+    String::from::utf8();
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP there is an associated function with a similar name: `from_utf8`
+    String::from::utf16();
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP there is an associated function with a similar name: `from_utf16`
+    String::from::method_that_doesnt_exist();
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP if there were a trait named `Example` with associated type `from`
+    str::into::string();
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP there is an associated function with a similar name: `into_string`
+    str::char::indices();
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP there is an associated function with a similar name: `char_indices`
+    Foo::bar::baz;
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP there is an associated function with a similar name: `bar_baz`
+    Foo::bar::quux;
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP there is an associated function with a similar name: `bar_quux`
+    Foo::bar::fizz;
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP if there were a trait named `Example` with associated type `bar`
+    i32::wrapping::add;
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP there is an associated function with a similar name: `wrapping_add`
+    i32::wrapping::method_that_doesnt_exist;
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP if there were a trait named `Example` with associated type `wrapping`
+
+    // this one ideally should suggest `downcast_mut_unchecked`
+    <dyn std::any::Any>::downcast::mut_unchecked;
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP if there were a trait named `Example` with associated type `downcast`
+}
diff --git a/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.stderr b/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.stderr
new file mode 100644
index 00000000000..5863aa28f41
--- /dev/null
+++ b/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.stderr
@@ -0,0 +1,135 @@
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:13:5
+   |
+LL |     String::from::utf8;
+   |     ^^^^^^^^^^^^
+   |
+help: there is an associated function with a similar name: `from_utf8`
+   |
+LL |     String::from_utf8;
+   |             ~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:16:5
+   |
+LL |     String::from::utf8();
+   |     ^^^^^^^^^^^^
+   |
+help: there is an associated function with a similar name: `from_utf8`
+   |
+LL |     String::from_utf8();
+   |             ~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:19:5
+   |
+LL |     String::from::utf16();
+   |     ^^^^^^^^^^^^
+   |
+help: there is an associated function with a similar name: `from_utf16`
+   |
+LL |     String::from_utf16();
+   |             ~~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:22:5
+   |
+LL |     String::from::method_that_doesnt_exist();
+   |     ^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `from` implemented for `String`, you could use the fully-qualified path
+   |
+LL |     <String as Example>::from::method_that_doesnt_exist();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:25:5
+   |
+LL |     str::into::string();
+   |     ^^^^^^^^^
+   |
+help: there is an associated function with a similar name: `into_string`
+   |
+LL |     str::into_string();
+   |          ~~~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:28:5
+   |
+LL |     str::char::indices();
+   |     ^^^^^^^^^
+   |
+help: there is an associated function with a similar name: `char_indices`
+   |
+LL |     str::char_indices();
+   |          ~~~~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:31:5
+   |
+LL |     Foo::bar::baz;
+   |     ^^^^^^^^
+   |
+help: there is an associated function with a similar name: `bar_baz`
+   |
+LL |     Foo::bar_baz;
+   |          ~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:34:5
+   |
+LL |     Foo::bar::quux;
+   |     ^^^^^^^^
+   |
+help: there is an associated function with a similar name: `bar_quux`
+   |
+LL |     Foo::bar_quux;
+   |          ~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:37:5
+   |
+LL |     Foo::bar::fizz;
+   |     ^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `bar` implemented for `Foo`, you could use the fully-qualified path
+   |
+LL |     <Foo as Example>::bar::fizz;
+   |     ~~~~~~~~~~~~~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:40:5
+   |
+LL |     i32::wrapping::add;
+   |     ^^^^^^^^^^^^^
+   |
+help: there is an associated function with a similar name: `wrapping_add`
+   |
+LL |     i32::wrapping_add;
+   |          ~~~~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:43:5
+   |
+LL |     i32::wrapping::method_that_doesnt_exist;
+   |     ^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `wrapping` implemented for `i32`, you could use the fully-qualified path
+   |
+LL |     <i32 as Example>::wrapping::method_that_doesnt_exist;
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:48:5
+   |
+LL |     <dyn std::any::Any>::downcast::mut_unchecked;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `downcast` implemented for `(dyn Any + 'static)`, you could use the fully-qualified path
+   |
+LL |     <(dyn Any + 'static) as Example>::downcast::mut_unchecked;
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0223`.
diff --git a/tests/ui/suggestions/import-visible-path-39175.fixed b/tests/ui/suggestions/import-visible-path-39175.fixed
new file mode 100644
index 00000000000..1f2b5b8b0ce
--- /dev/null
+++ b/tests/ui/suggestions/import-visible-path-39175.fixed
@@ -0,0 +1,16 @@
+// This test ignores some platforms as the particular extension trait used
+// to demonstrate the issue is only available on unix. This is fine as
+// the fix to suggested paths is not platform-dependent and will apply on
+// these platforms also.
+
+//@ run-rustfix
+//@ only-unix (the diagnostics is influenced by `use std::os::unix::process::CommandExt;`)
+
+use std::os::unix::process::CommandExt;
+use std::process::Command;
+// use std::os::unix::process::CommandExt;
+
+fn main() {
+    let _ = Command::new("echo").arg("hello").exec();
+//~^ ERROR no method named `exec`
+}
diff --git a/tests/ui/issues/issue-39175.rs b/tests/ui/suggestions/import-visible-path-39175.rs
index 7b801317b71..a7e6134b2d9 100644
--- a/tests/ui/issues/issue-39175.rs
+++ b/tests/ui/suggestions/import-visible-path-39175.rs
@@ -3,14 +3,13 @@
 // the fix to suggested paths is not platform-dependent and will apply on
 // these platforms also.
 
-//@ ignore-windows
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ run-rustfix
+//@ only-unix (the diagnostics is influenced by `use std::os::unix::process::CommandExt;`)
 
 use std::process::Command;
 // use std::os::unix::process::CommandExt;
 
 fn main() {
-    Command::new("echo").arg("hello").exec();
+    let _ = Command::new("echo").arg("hello").exec();
 //~^ ERROR no method named `exec`
 }
diff --git a/tests/ui/issues/issue-39175.stderr b/tests/ui/suggestions/import-visible-path-39175.stderr
index bbe8badb652..0b558ca4b52 100644
--- a/tests/ui/issues/issue-39175.stderr
+++ b/tests/ui/suggestions/import-visible-path-39175.stderr
@@ -1,8 +1,8 @@
 error[E0599]: no method named `exec` found for mutable reference `&mut Command` in the current scope
-  --> $DIR/issue-39175.rs:14:39
+  --> $DIR/import-visible-path-39175.rs:13:47
    |
-LL |     Command::new("echo").arg("hello").exec();
-   |                                       ^^^^
+LL |     let _ = Command::new("echo").arg("hello").exec();
+   |                                               ^^^^
    |
    = help: items from traits can only be used if the trait is in scope
 help: there is a method `pre_exec` with a similar name, but with different arguments
diff --git a/tests/ui/suggestions/issue-109195.rs b/tests/ui/suggestions/issue-109195.rs
deleted file mode 100644
index cc499b0d776..00000000000
--- a/tests/ui/suggestions/issue-109195.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-fn main() {
-    String::from::utf8;
-    //~^ ERROR ambiguous associated type [E0223]
-    //~| HELP there is an associated function with a similar name: `from_utf8`
-    String::from::utf8();
-    //~^ ERROR ambiguous associated type [E0223]
-    //~| HELP there is an associated function with a similar name: `from_utf8`
-    String::from::utf16();
-    //~^ ERROR ambiguous associated type [E0223]
-    //~| HELP there is an associated function with a similar name: `from_utf16`
-    String::from::method_that_doesnt_exist();
-    //~^ ERROR ambiguous associated type [E0223]
-    //~| HELP if there were a trait named `Example` with associated type `from`
-    str::from::utf8();
-    //~^ ERROR ambiguous associated type [E0223]
-    //~| HELP if there were a trait named `Example` with associated type `from`
-    str::from::utf8_mut();
-    //~^ ERROR ambiguous associated type [E0223]
-    //~| HELP if there were a trait named `Example` with associated type `from`
-}
diff --git a/tests/ui/suggestions/issue-109195.stderr b/tests/ui/suggestions/issue-109195.stderr
deleted file mode 100644
index 10cf9cfd28c..00000000000
--- a/tests/ui/suggestions/issue-109195.stderr
+++ /dev/null
@@ -1,69 +0,0 @@
-error[E0223]: ambiguous associated type
-  --> $DIR/issue-109195.rs:2:5
-   |
-LL |     String::from::utf8;
-   |     ^^^^^^^^^^^^
-   |
-help: there is an associated function with a similar name: `from_utf8`
-   |
-LL |     String::from_utf8;
-   |             ~~~~~~~~~
-
-error[E0223]: ambiguous associated type
-  --> $DIR/issue-109195.rs:5:5
-   |
-LL |     String::from::utf8();
-   |     ^^^^^^^^^^^^
-   |
-help: there is an associated function with a similar name: `from_utf8`
-   |
-LL |     String::from_utf8();
-   |             ~~~~~~~~~
-
-error[E0223]: ambiguous associated type
-  --> $DIR/issue-109195.rs:8:5
-   |
-LL |     String::from::utf16();
-   |     ^^^^^^^^^^^^
-   |
-help: there is an associated function with a similar name: `from_utf16`
-   |
-LL |     String::from_utf16();
-   |             ~~~~~~~~~~
-
-error[E0223]: ambiguous associated type
-  --> $DIR/issue-109195.rs:11:5
-   |
-LL |     String::from::method_that_doesnt_exist();
-   |     ^^^^^^^^^^^^
-   |
-help: if there were a trait named `Example` with associated type `from` implemented for `String`, you could use the fully-qualified path
-   |
-LL |     <String as Example>::from::method_that_doesnt_exist();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error[E0223]: ambiguous associated type
-  --> $DIR/issue-109195.rs:14:5
-   |
-LL |     str::from::utf8();
-   |     ^^^^^^^^^
-   |
-help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path
-   |
-LL |     <str as Example>::from::utf8();
-   |     ~~~~~~~~~~~~~~~~~~~~~~
-
-error[E0223]: ambiguous associated type
-  --> $DIR/issue-109195.rs:17:5
-   |
-LL |     str::from::utf8_mut();
-   |     ^^^^^^^^^
-   |
-help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path
-   |
-LL |     <str as Example>::from::utf8_mut();
-   |     ~~~~~~~~~~~~~~~~~~~~~~
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0223`.
diff --git a/tests/ui/test-attrs/terse.rs b/tests/ui/test-attrs/terse.rs
index 6c3f29ed10f..6e605f994f2 100644
--- a/tests/ui/test-attrs/terse.rs
+++ b/tests/ui/test-attrs/terse.rs
@@ -4,7 +4,7 @@
 //@ check-run-results
 //@ exec-env:RUST_BACKTRACE=0
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
-//@ ignore-emscripten no threads support
+//@ needs-threads
 //@ needs-unwind
 
 #[test]
diff --git a/tests/ui/test-attrs/test-panic-abort-disabled.rs b/tests/ui/test-attrs/test-panic-abort-disabled.rs
index fbe3d7d5d18..05dd9395c2b 100644
--- a/tests/ui/test-attrs/test-panic-abort-disabled.rs
+++ b/tests/ui/test-attrs/test-panic-abort-disabled.rs
@@ -4,8 +4,9 @@
 //@ run-flags: --test-threads=1
 
 //@ needs-unwind
-//@ ignore-wasm no panic or subprocess support
-//@ ignore-emscripten no panic or subprocess support
+//@ ignore-wasm no panic support
+//@ ignore-emscripten no panic support
+//@ needs-subprocess
 
 #![cfg(test)]
 
diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.rs b/tests/ui/test-attrs/test-panic-abort-nocapture.rs
index 4377ae1ac3b..f7e15dbdbc3 100644
--- a/tests/ui/test-attrs/test-panic-abort-nocapture.rs
+++ b/tests/ui/test-attrs/test-panic-abort-nocapture.rs
@@ -7,9 +7,9 @@
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
 
 //@ ignore-android #120567
-//@ ignore-wasm no panic or subprocess support
-//@ ignore-emscripten no panic or subprocess support
-//@ ignore-sgx no subprocess support
+//@ ignore-wasm no panic support
+//@ ignore-emscripten no panic support
+//@ needs-subprocess
 
 #![cfg(test)]
 
diff --git a/tests/ui/test-attrs/test-panic-abort.rs b/tests/ui/test-attrs/test-panic-abort.rs
index 3d203e059a4..951cf54346b 100644
--- a/tests/ui/test-attrs/test-panic-abort.rs
+++ b/tests/ui/test-attrs/test-panic-abort.rs
@@ -7,9 +7,9 @@
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
 
 //@ ignore-android #120567
-//@ ignore-wasm no panic or subprocess support
-//@ ignore-emscripten no panic or subprocess support
-//@ ignore-sgx no subprocess support
+//@ ignore-wasm no panic support
+//@ ignore-emscripten no panic support
+//@ needs-subprocess
 
 #![cfg(test)]
 #![feature(test)]
diff --git a/tests/ui/test-attrs/test-thread-capture.rs b/tests/ui/test-attrs/test-thread-capture.rs
index c56f87f2dda..0a5b1e9816f 100644
--- a/tests/ui/test-attrs/test-thread-capture.rs
+++ b/tests/ui/test-attrs/test-thread-capture.rs
@@ -4,7 +4,7 @@
 //@ check-run-results
 //@ exec-env:RUST_BACKTRACE=0
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
-//@ ignore-emscripten no threads support
+//@ needs-threads
 //@ needs-unwind
 
 #[test]
diff --git a/tests/ui/test-attrs/test-thread-nocapture.rs b/tests/ui/test-attrs/test-thread-nocapture.rs
index 5b82e9b2720..ce5db7bf1c3 100644
--- a/tests/ui/test-attrs/test-thread-nocapture.rs
+++ b/tests/ui/test-attrs/test-thread-nocapture.rs
@@ -4,7 +4,7 @@
 //@ check-run-results
 //@ exec-env:RUST_BACKTRACE=0
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
-//@ ignore-emscripten no threads support
+//@ needs-threads
 //@ needs-unwind
 
 #[test]
diff --git a/tests/ui/threads-sendsync/eprint-on-tls-drop.rs b/tests/ui/threads-sendsync/eprint-on-tls-drop.rs
index 82abf21df3f..e85c7c83339 100644
--- a/tests/ui/threads-sendsync/eprint-on-tls-drop.rs
+++ b/tests/ui/threads-sendsync/eprint-on-tls-drop.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ needs-threads
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::cell::RefCell;
 use std::env;
diff --git a/tests/ui/threads-sendsync/issue-24313.rs b/tests/ui/threads-sendsync/issue-24313.rs
index 99c6c4a5e12..83ab5122e82 100644
--- a/tests/ui/threads-sendsync/issue-24313.rs
+++ b/tests/ui/threads-sendsync/issue-24313.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ needs-threads
-//@ ignore-sgx no processes
+//@ needs-subprocess
 
 use std::process::Command;
 use std::{env, thread};
diff --git a/tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs b/tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
new file mode 100644
index 00000000000..dc96652f82f
--- /dev/null
+++ b/tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+// `(): Trait` is a global where-bound with a projection bound.
+// This previously resulted in ambiguity as we considered both
+// the impl and the where-bound while normalizing.
+
+trait Trait {
+    type Assoc;
+}
+impl Trait for () {
+    type Assoc = &'static ();
+}
+
+fn foo<'a>(x: <() as Trait>::Assoc)
+where
+    (): Trait<Assoc = &'a ()>,
+{
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/issue-77179.stderr b/tests/ui/type-alias-impl-trait/issue-77179.stderr
index 85a943c26e2..16bbc996d90 100644
--- a/tests/ui/type-alias-impl-trait/issue-77179.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-77179.stderr
@@ -28,10 +28,7 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures
   --> $DIR/issue-77179.rs:18:25
    |
 LL |     fn bar() -> Pointer<_>;
-   |                         ^
-   |                         |
-   |                         not allowed in type signatures
-   |                         help: use type parameters instead: `T`
+   |                         ^ not allowed in type signatures
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs
index 55f45ade388..c5f8b2764ec 100644
--- a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs
+++ b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs
@@ -4,7 +4,7 @@
 type Pat<const START: u32, const END: u32> =
     std::pat::pattern_type!(u32 is START::<(), i32, 2>..=END::<_, Assoc = ()>);
 //~^ ERROR type and const arguments are not allowed on const parameter `START`
-//~| ERROR type arguments are not allowed on const parameter `END`
+//~| ERROR generic arguments are not allowed on const parameter `END`
 //~| ERROR associated item constraints are not allowed here
 
 fn main() {}
diff --git a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr
index 7f4e6e314f5..f31809bf397 100644
--- a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr
+++ b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr
@@ -12,11 +12,11 @@ note: const parameter `START` defined here
 LL | type Pat<const START: u32, const END: u32> =
    |                ^^^^^
 
-error[E0109]: type arguments are not allowed on const parameter `END`
+error[E0109]: generic arguments are not allowed on const parameter `END`
   --> $DIR/bad_const_generics_args_on_const_param.rs:5:64
    |
 LL |     std::pat::pattern_type!(u32 is START::<(), i32, 2>..=END::<_, Assoc = ()>);
-   |                                                          ---   ^ type argument not allowed
+   |                                                          ---   ^ generic argument not allowed
    |                                                          |
    |                                                          not allowed on const parameter `END`
    |
diff --git a/tests/ui/typeck/ice-self-mismatch-const-generics.stderr b/tests/ui/typeck/ice-self-mismatch-const-generics.stderr
index c502ea4565f..068cf3ee903 100644
--- a/tests/ui/typeck/ice-self-mismatch-const-generics.stderr
+++ b/tests/ui/typeck/ice-self-mismatch-const-generics.stderr
@@ -8,8 +8,8 @@ LL |     pub fn new(thing: T) -> GenericStruct<1, T> {
 LL |         Self { thing }
    |         ^^^^^^^^^^^^^^ expected `1`, found `0`
    |
-   = note: expected struct `GenericStruct<_, 1>`
-              found struct `GenericStruct<_, 0>`
+   = note: expected struct `GenericStruct<1, _>`
+              found struct `GenericStruct<0, _>`
 help: use the type name directly
    |
 LL |         GenericStruct::<1, T> { thing }
@@ -25,8 +25,8 @@ LL |     pub fn new(thing: T) -> GenericStruct2<1, T> {
 LL |         Self { 0: thing }
    |         ^^^^^^^^^^^^^^^^^ expected `1`, found `0`
    |
-   = note: expected struct `GenericStruct2<_, 1>`
-              found struct `GenericStruct2<_, 0>`
+   = note: expected struct `GenericStruct2<1, _>`
+              found struct `GenericStruct2<0, _>`
 help: use the type name directly
    |
 LL |         GenericStruct2::<1, T> { 0: thing }
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr
index c97b9312076..d2a850d7dbf 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr
@@ -507,22 +507,12 @@ LL | impl BadTrait<_> for BadStruct<_> {}
    |               ^                ^ not allowed in type signatures
    |               |
    |               not allowed in type signatures
-   |
-help: use type parameters instead
-   |
-LL | impl<T> BadTrait<T> for BadStruct<T> {}
-   |     +++          ~                ~
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:162:34
    |
 LL | fn impl_trait() -> impl BadTrait<_> {
    |                                  ^ not allowed in type signatures
-   |
-help: use type parameters instead
-   |
-LL | fn impl_trait<T>() -> impl BadTrait<T> {
-   |              +++                    ~
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/typeck_type_placeholder_item.rs:167:25
diff --git a/tests/ui/wait-forked-but-failed-child.rs b/tests/ui/wait-forked-but-failed-child.rs
index dd6a7fa0e65..04f1c1a65d5 100644
--- a/tests/ui/wait-forked-but-failed-child.rs
+++ b/tests/ui/wait-forked-but-failed-child.rs
@@ -1,6 +1,5 @@
 //@ run-pass
-//@ ignore-wasm32 no processes
-//@ ignore-sgx no processes
+//@ needs-subprocess
 //@ ignore-vxworks no 'ps'
 //@ ignore-fuchsia no 'ps'
 //@ ignore-nto no 'ps'