about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml19
-rw-r--r--compiler/rustc_abi/src/callconv.rs77
-rw-r--r--compiler/rustc_abi/src/callconv/reg.rs63
-rw-r--r--compiler/rustc_abi/src/extern_abi.rs (renamed from compiler/rustc_abi/src/extern_abi/mod.rs)0
-rw-r--r--compiler/rustc_abi/src/layout/ty.rs12
-rw-r--r--compiler/rustc_borrowck/src/type_check/opaque_types.rs12
-rw-r--r--compiler/rustc_codegen_gcc/src/base.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/mono_item.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs29
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs29
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/naked_asm.rs3
-rw-r--r--compiler/rustc_feature/src/accepted.rs5
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_feature/src/removed.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs5
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs23
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs78
-rw-r--r--compiler/rustc_infer/src/infer/outlives/for_liveness.rs10
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs6
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs8
-rw-r--r--compiler/rustc_interface/src/passes.rs4
-rw-r--r--compiler/rustc_lint/src/deref_into_dyn_supertrait.rs25
-rw-r--r--compiler/rustc_lint/src/early.rs8
-rw-r--r--compiler/rustc_lint/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/passes.rs2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp31
-rw-r--r--compiler/rustc_middle/src/lib.rs2
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs8
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs24
-rw-r--r--compiler/rustc_middle/src/ty/util.rs23
-rw-r--r--compiler/rustc_mir_build/messages.ftl11
-rw-r--r--compiler/rustc_mir_build/src/check_tail_calls.rs51
-rw-r--r--compiler/rustc_mir_build/src/errors.rs60
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs146
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs6
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs2
-rw-r--r--compiler/rustc_parse/src/lexer/unicode_chars.rs2
-rw-r--r--compiler/rustc_target/src/asm/mod.rs2
-rw-r--r--compiler/rustc_target/src/callconv/aarch64.rs3
-rw-r--r--compiler/rustc_target/src/callconv/amdgpu.rs3
-rw-r--r--compiler/rustc_target/src/callconv/arm.rs3
-rw-r--r--compiler/rustc_target/src/callconv/loongarch.rs23
-rw-r--r--compiler/rustc_target/src/callconv/mips.rs3
-rw-r--r--compiler/rustc_target/src/callconv/mips64.rs33
-rw-r--r--compiler/rustc_target/src/callconv/mod.rs20
-rw-r--r--compiler/rustc_target/src/callconv/nvptx64.rs5
-rw-r--r--compiler/rustc_target/src/callconv/powerpc64.rs3
-rw-r--r--compiler/rustc_target/src/callconv/riscv.rs23
-rw-r--r--compiler/rustc_target/src/callconv/s390x.rs3
-rw-r--r--compiler/rustc_target/src/callconv/sparc.rs3
-rw-r--r--compiler/rustc_target/src/callconv/sparc64.rs40
-rw-r--r--compiler/rustc_target/src/callconv/wasm.rs3
-rw-r--r--compiler/rustc_target/src/callconv/x86.rs22
-rw-r--r--compiler/rustc_target/src/callconv/x86_64.rs16
-rw-r--r--compiler/rustc_target/src/callconv/xtensa.rs3
-rw-r--r--compiler/rustc_target/src/lib.rs5
-rw-r--r--compiler/rustc_target/src/spec/base/aix.rs3
-rw-r--r--compiler/rustc_target/src/spec/base/bpf.rs3
-rw-r--r--compiler/rustc_target/src/spec/base/xtensa.rs3
-rw-r--r--compiler/rustc_target/src/spec/mod.rs45
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs2
-rw-r--r--compiler/rustc_target/src/target_features.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs63
-rw-r--r--compiler/rustc_type_ir/src/interner.rs6
-rw-r--r--compiler/rustc_type_ir/src/outlives.rs18
-rw-r--r--compiler/rustc_type_ir/src/predicate.rs11
-rw-r--r--compiler/rustc_type_ir/src/relate.rs28
-rw-r--r--compiler/rustc_type_ir/src/solve/mod.rs4
-rw-r--r--library/alloc/src/ffi/c_str.rs5
-rw-r--r--library/alloc/src/rc.rs4
-rw-r--r--library/alloc/tests/str.rs22
-rw-r--r--library/coretests/tests/bool.rs8
-rw-r--r--library/coretests/tests/lib.rs1
-rw-r--r--library/coretests/tests/ptr.rs6
-rw-r--r--library/std/src/fs/tests.rs2
-rw-r--r--library/std/src/io/cursor.rs4
-rw-r--r--library/std/src/io/mod.rs2
-rw-r--r--library/std/src/lib.rs25
-rw-r--r--library/std/src/net/test.rs33
-rw-r--r--library/std/src/os/unix/fs/tests.rs4
-rw-r--r--library/std/src/os/unix/net/tests.rs2
-rw-r--r--library/std/src/process/tests.rs152
-rw-r--r--library/std/src/sys/io/io_slice/iovec.rs (renamed from library/std/src/sys/pal/hermit/io.rs)14
-rw-r--r--library/std/src/sys/io/io_slice/unsupported.rs (renamed from library/std/src/sys/pal/unsupported/io.rs)4
-rw-r--r--library/std/src/sys/io/io_slice/wasi.rs (renamed from library/std/src/sys/pal/wasi/io.rs)8
-rw-r--r--library/std/src/sys/io/io_slice/windows.rs (renamed from library/std/src/sys/pal/solid/io.rs)38
-rw-r--r--library/std/src/sys/io/is_terminal/hermit.rs6
-rw-r--r--library/std/src/sys/io/is_terminal/isatty.rs6
-rw-r--r--library/std/src/sys/io/is_terminal/unsupported.rs3
-rw-r--r--library/std/src/sys/io/is_terminal/windows.rs (renamed from library/std/src/sys/pal/windows/io.rs)84
-rw-r--r--library/std/src/sys/io/mod.rs44
-rw-r--r--library/std/src/sys/mod.rs1
-rw-r--r--library/std/src/sys/net/connection/uefi/mod.rs369
-rw-r--r--library/std/src/sys/net/mod.rs5
-rw-r--r--library/std/src/sys/pal/hermit/mod.rs1
-rw-r--r--library/std/src/sys/pal/sgx/mod.rs2
-rw-r--r--library/std/src/sys/pal/sgx/stdio.rs2
-rw-r--r--library/std/src/sys/pal/solid/mod.rs1
-rw-r--r--library/std/src/sys/pal/teeos/mod.rs2
-rw-r--r--library/std/src/sys/pal/uefi/mod.rs2
-rw-r--r--library/std/src/sys/pal/unix/io.rs87
-rw-r--r--library/std/src/sys/pal/unix/kernel_copy/tests.rs2
-rw-r--r--library/std/src/sys/pal/unix/mod.rs1
-rw-r--r--library/std/src/sys/pal/unix/stdio.rs2
-rw-r--r--library/std/src/sys/pal/unsupported/mod.rs1
-rw-r--r--library/std/src/sys/pal/wasi/mod.rs1
-rw-r--r--library/std/src/sys/pal/wasi/stdio.rs2
-rw-r--r--library/std/src/sys/pal/wasip2/mod.rs2
-rw-r--r--library/std/src/sys/pal/wasm/mod.rs2
-rw-r--r--library/std/src/sys/pal/windows/mod.rs1
-rw-r--r--library/std/src/sys/pal/windows/process/tests.rs2
-rw-r--r--library/std/src/sys/pal/xous/mod.rs2
-rw-r--r--library/std/src/sys/pal/zkvm/mod.rs2
-rw-r--r--library/std/src/sys/pal/zkvm/stdio.rs2
-rw-r--r--library/std/src/sys_common/io.rs49
-rw-r--r--library/std/src/sys_common/mod.rs1
-rw-r--r--library/std/src/test_helpers.rs65
-rw-r--r--library/std/tests/common/mod.rs2
-rw-r--r--library/std/tests/istr.rs4
-rw-r--r--library/std/tests/seq-compare.rs22
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs3
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs2
-rw-r--r--src/bootstrap/src/lib.rs2
-rw-r--r--src/bootstrap/src/utils/exec.rs5
-rw-r--r--src/ci/docker/host-x86_64/dist-various-2/Dockerfile6
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile6
-rwxr-xr-xsrc/ci/docker/scripts/freebsd-toolchain.sh6
-rw-r--r--src/ci/github-actions/jobs.yml2
-rw-r--r--src/doc/rustc/src/platform-support.md2
-rw-r--r--src/doc/unstable-book/src/language-features/trait-upcasting.md26
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/empty_line_after.rs345
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs81
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_line_after.rs492
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs2
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs16
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr14
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed9
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed9
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs10
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr51
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr30
-rw-r--r--src/tools/clippy/tests/ui/suspicious_doc_comments.fixed1
-rw-r--r--src/tools/clippy/tests/ui/suspicious_doc_comments.rs1
-rw-r--r--src/tools/clippy/tests/ui/suspicious_doc_comments.stderr18
-rw-r--r--src/tools/miri/src/lib.rs2
-rw-r--r--src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs3
-rw-r--r--src/tools/miri/tests/pass/binops.rs30
-rw-r--r--src/tools/miri/tests/pass/box-custom-alloc.rs3
-rw-r--r--src/tools/miri/tests/pass/dyn-upcast.rs3
-rwxr-xr-xsrc/tools/publish_toolstate.py19
-rw-r--r--tests/codegen/debug-fndef-size.rs8
-rw-r--r--tests/codegen/terminating-catchpad.rs37
-rw-r--r--tests/codegen/vtable-upcast.rs1
-rw-r--r--tests/crashes/131886.rs2
-rw-r--r--tests/crashes/134336.rs11
-rw-r--r--tests/run-make/libs-through-symlinks/rmake.rs1
-rw-r--r--tests/ui/argument-suggestions/extern-fn-arg-names.stderr2
-rw-r--r--tests/ui/binding/expr-match-generic.rs2
-rw-r--r--tests/ui/binding/expr-match.rs13
-rw-r--r--tests/ui/binop/binops.rs30
-rw-r--r--tests/ui/binop/structured-compare.rs14
-rw-r--r--tests/ui/c-variadic/variadic-ffi-1.stderr4
-rw-r--r--tests/ui/cfg/conditional-compile.rs2
-rw-r--r--tests/ui/codegen/issue-99551.rs1
-rw-r--r--tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs4
-rw-r--r--tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr11
-rw-r--r--tests/ui/dyn-star/upcast.rs2
-rw-r--r--tests/ui/dyn-star/upcast.stderr2
-rw-r--r--tests/ui/error-codes/E0060.stderr2
-rw-r--r--tests/ui/explicit-tail-calls/become-trait-fn.rs19
-rw-r--r--tests/ui/explicit-tail-calls/callee_is_track_caller.rs15
-rw-r--r--tests/ui/explicit-tail-calls/caller_is_track_caller.rs16
-rw-r--r--tests/ui/explicit-tail-calls/caller_is_track_caller.stderr14
-rw-r--r--tests/ui/expr/block.rs2
-rw-r--r--tests/ui/expr/if/expr-if.rs18
-rw-r--r--tests/ui/feature-gates/feature-gate-trait_upcasting.rs13
-rw-r--r--tests/ui/feature-gates/feature-gate-trait_upcasting.stderr14
-rw-r--r--tests/ui/fn/param-mismatch-foreign.rs11
-rw-r--r--tests/ui/fn/param-mismatch-foreign.stderr19
-rw-r--r--tests/ui/for-loop-while/break.rs8
-rw-r--r--tests/ui/for-loop-while/while-cont.rs2
-rw-r--r--tests/ui/for-loop-while/while-loop-constraints-2.rs2
-rw-r--r--tests/ui/generics/generic-tag-match.rs2
-rw-r--r--tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs19
-rw-r--r--tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs18
-rw-r--r--tests/ui/impl-trait/unsized_coercion5.old.stderr2
-rw-r--r--tests/ui/impl-trait/unsized_coercion5.rs2
-rw-r--r--tests/ui/iterators/iter-range.rs2
-rw-r--r--tests/ui/linkage-attr/linkage-attr-does-not-panic-llvm-issue-33992.rs3
-rw-r--r--tests/ui/macros/syntax-extension-source-utils.rs4
-rw-r--r--tests/ui/mismatched_types/issue-26480.stderr2
-rw-r--r--tests/ui/never_type/dont-suggest-turbofish-from-expansion.rs20
-rw-r--r--tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr26
-rw-r--r--tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr4
-rw-r--r--tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr4
-rw-r--r--tests/ui/numbers-arithmetic/arith-unsigned.rs24
-rw-r--r--tests/ui/numbers-arithmetic/float-nan.rs2
-rw-r--r--tests/ui/numbers-arithmetic/float2.rs10
-rw-r--r--tests/ui/numbers-arithmetic/floatlits.rs8
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr48
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs33
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr6
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr121
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed132
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs130
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr423
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs14
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr77
-rw-r--r--tests/ui/process/win-creation-flags.rs51
-rw-r--r--tests/ui/process/win-proc-thread-attributes.rs118
-rw-r--r--tests/ui/sanitizer/cfi/supertraits.rs1
-rw-r--r--tests/ui/self/arbitrary_self_types_dispatch_to_vtable.rs33
-rw-r--r--tests/ui/structs-enums/class-impl-very-parameterized-trait.rs2
-rw-r--r--tests/ui/structs-enums/class-implement-trait-cross-crate.rs4
-rw-r--r--tests/ui/structs-enums/class-implement-traits.rs2
-rw-r--r--tests/ui/structs-enums/classes-cross-crate.rs4
-rw-r--r--tests/ui/structs-enums/classes.rs4
-rw-r--r--tests/ui/structs-enums/tag.rs2
-rw-r--r--tests/ui/suggestions/suggest-null-ptr.stderr8
-rw-r--r--tests/ui/tail-cps.rs2
-rw-r--r--tests/ui/traits/next-solver/normalize/normalize-unsize-rhs.rs1
-rw-r--r--tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs1
-rw-r--r--tests/ui/traits/next-solver/upcast-right-substs.rs1
-rw-r--r--tests/ui/traits/trait-upcasting/add-supertrait-auto-traits.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs1
-rw-r--r--tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr2
-rw-r--r--tests/ui/traits/trait-upcasting/basic.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs1
-rw-r--r--tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs35
-rw-r--r--tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr19
-rw-r--r--tests/ui/traits/trait-upcasting/deref-upcast-shadowing-lint.rs17
-rw-r--r--tests/ui/traits/trait-upcasting/deref-upcast-shadowing-lint.stderr17
-rw-r--r--tests/ui/traits/trait-upcasting/diamond.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/fewer-associated.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr2
-rw-r--r--tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr2
-rw-r--r--tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/illegal-upcast-to-impl-opaque.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs5
-rw-r--r--tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr2
-rw-r--r--tests/ui/traits/trait-upcasting/invalid-upcast.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/invalid-upcast.stderr30
-rw-r--r--tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs1
-rw-r--r--tests/ui/traits/trait-upcasting/issue-11515.current.stderr14
-rw-r--r--tests/ui/traits/trait-upcasting/issue-11515.next.stderr14
-rw-r--r--tests/ui/traits/trait-upcasting/issue-11515.rs3
-rw-r--r--tests/ui/traits/trait-upcasting/lifetime.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/lifetime.stderr4
-rw-r--r--tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs6
-rw-r--r--tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr14
-rw-r--r--tests/ui/traits/trait-upcasting/migrate-lint-deny.rs25
-rw-r--r--tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr19
-rw-r--r--tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs4
-rw-r--r--tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr12
-rw-r--r--tests/ui/traits/trait-upcasting/mono-impossible.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs1
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr2
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs6
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.rs1
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.stderr4
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.rs6
-rw-r--r--tests/ui/traits/trait-upcasting/normalization.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/prefer-lower-candidates.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/replace-vptr.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/replace-vptr.stderr4
-rw-r--r--tests/ui/traits/trait-upcasting/struct.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/subtrait-method.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/subtrait-method.stderr20
-rw-r--r--tests/ui/traits/trait-upcasting/supertraits-modulo-inner-binder.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr2
-rw-r--r--tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr2
-rw-r--r--tests/ui/traits/trait-upcasting/type-checking-test-1.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/type-checking-test-2.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/type-checking-test-2.stderr4
-rw-r--r--tests/ui/traits/trait-upcasting/type-checking-test-3.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/type-checking-test-3.stderr4
-rw-r--r--tests/ui/traits/trait-upcasting/type-checking-test-4.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/type-checking-test-4.stderr12
-rw-r--r--tests/ui/traits/trait-upcasting/type-checking-test-opaques.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs2
-rw-r--r--tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr14
-rw-r--r--tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr14
-rw-r--r--tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs2
-rw-r--r--tests/ui/traits/upcast_reorder.rs2
-rw-r--r--tests/ui/traits/upcast_soundness_bug.rs1
-rw-r--r--tests/ui/traits/upcast_soundness_bug.stderr2
-rw-r--r--tests/ui/wait-forked-but-failed-child.rs11
-rw-r--r--tests/ui/weird-exprs.rs6
-rw-r--r--triagebot.toml20
306 files changed, 3404 insertions, 2317 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7a46d123c5d..0934e42b277 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -62,9 +62,6 @@ jobs:
     name: ${{ matrix.full_name }}
     needs: [ calculate_matrix ]
     runs-on: "${{ matrix.os }}"
-    defaults:
-      run:
-        shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}
     timeout-minutes: 360
     env:
       CI_JOB_NAME: ${{ matrix.name }}
@@ -80,22 +77,6 @@ jobs:
         # Check the `calculate_matrix` job to see how is the matrix defined.
         include: ${{ fromJSON(needs.calculate_matrix.outputs.jobs) }}
     steps:
-      - if: contains(matrix.os, 'windows')
-        uses: msys2/setup-msys2@v2.22.0
-        with:
-          # i686 jobs use mingw32. x86_64 and cross-compile jobs use mingw64.
-          msystem: ${{ contains(matrix.name, 'i686') && 'mingw32' || 'mingw64' }}
-          # don't try to download updates for already installed packages
-          update: false
-          # don't try to use the msys that comes built-in to the github runner,
-          # so we can control what is installed (i.e. not python)
-          release: true
-          # Inherit the full path from the Windows environment, with MSYS2's */bin/
-          # dirs placed in front. This lets us run Windows-native Python etc.
-          path-type: inherit
-          install: >
-            make
-
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
 
diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs
index 400395f99ff..daa365bf6e1 100644
--- a/compiler/rustc_abi/src/callconv.rs
+++ b/compiler/rustc_abi/src/callconv.rs
@@ -1,73 +1,10 @@
-mod abi {
-    pub(crate) use crate::Primitive::*;
-    pub(crate) use crate::Variants;
-}
-
-#[cfg(feature = "nightly")]
-use rustc_macros::HashStable_Generic;
-
-use crate::{Align, HasDataLayout, Size};
 #[cfg(feature = "nightly")]
 use crate::{BackendRepr, FieldsShape, TyAbiInterface, TyAndLayout};
+use crate::{Primitive, Size, Variants};
 
-#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub enum RegKind {
-    Integer,
-    Float,
-    Vector,
-}
-
-#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub struct Reg {
-    pub kind: RegKind,
-    pub size: Size,
-}
-
-macro_rules! reg_ctor {
-    ($name:ident, $kind:ident, $bits:expr) => {
-        pub fn $name() -> Reg {
-            Reg { kind: RegKind::$kind, size: Size::from_bits($bits) }
-        }
-    };
-}
-
-impl Reg {
-    reg_ctor!(i8, Integer, 8);
-    reg_ctor!(i16, Integer, 16);
-    reg_ctor!(i32, Integer, 32);
-    reg_ctor!(i64, Integer, 64);
-    reg_ctor!(i128, Integer, 128);
-
-    reg_ctor!(f32, Float, 32);
-    reg_ctor!(f64, Float, 64);
-}
+mod reg;
 
-impl Reg {
-    pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
-        let dl = cx.data_layout();
-        match self.kind {
-            RegKind::Integer => match self.size.bits() {
-                1 => dl.i1_align.abi,
-                2..=8 => dl.i8_align.abi,
-                9..=16 => dl.i16_align.abi,
-                17..=32 => dl.i32_align.abi,
-                33..=64 => dl.i64_align.abi,
-                65..=128 => dl.i128_align.abi,
-                _ => panic!("unsupported integer: {self:?}"),
-            },
-            RegKind::Float => match self.size.bits() {
-                16 => dl.f16_align.abi,
-                32 => dl.f32_align.abi,
-                64 => dl.f64_align.abi,
-                128 => dl.f128_align.abi,
-                _ => panic!("unsupported float: {self:?}"),
-            },
-            RegKind::Vector => dl.vector_align(self.size).abi,
-        }
-    }
-}
+pub use reg::{Reg, RegKind};
 
 /// Return value from the `homogeneous_aggregate` test function.
 #[derive(Copy, Clone, Debug)]
@@ -134,8 +71,8 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
             // The primitive for this algorithm.
             BackendRepr::Scalar(scalar) => {
                 let kind = match scalar.primitive() {
-                    abi::Int(..) | abi::Pointer(_) => RegKind::Integer,
-                    abi::Float(_) => RegKind::Float,
+                    Primitive::Int(..) | Primitive::Pointer(_) => RegKind::Integer,
+                    Primitive::Float(_) => RegKind::Float,
                 };
                 Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
             }
@@ -206,8 +143,8 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
                 let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;
 
                 match &self.variants {
-                    abi::Variants::Single { .. } | abi::Variants::Empty => {}
-                    abi::Variants::Multiple { variants, .. } => {
+                    Variants::Single { .. } | Variants::Empty => {}
+                    Variants::Multiple { variants, .. } => {
                         // Treat enum variants like union members.
                         // HACK(eddyb) pretend the `enum` field (discriminant)
                         // is at the start of every variant (otherwise the gap
diff --git a/compiler/rustc_abi/src/callconv/reg.rs b/compiler/rustc_abi/src/callconv/reg.rs
new file mode 100644
index 00000000000..66f47c52c15
--- /dev/null
+++ b/compiler/rustc_abi/src/callconv/reg.rs
@@ -0,0 +1,63 @@
+#[cfg(feature = "nightly")]
+use rustc_macros::HashStable_Generic;
+
+use crate::{Align, HasDataLayout, Size};
+
+#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub enum RegKind {
+    Integer,
+    Float,
+    Vector,
+}
+
+#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct Reg {
+    pub kind: RegKind,
+    pub size: Size,
+}
+
+macro_rules! reg_ctor {
+    ($name:ident, $kind:ident, $bits:expr) => {
+        pub fn $name() -> Reg {
+            Reg { kind: RegKind::$kind, size: Size::from_bits($bits) }
+        }
+    };
+}
+
+impl Reg {
+    reg_ctor!(i8, Integer, 8);
+    reg_ctor!(i16, Integer, 16);
+    reg_ctor!(i32, Integer, 32);
+    reg_ctor!(i64, Integer, 64);
+    reg_ctor!(i128, Integer, 128);
+
+    reg_ctor!(f32, Float, 32);
+    reg_ctor!(f64, Float, 64);
+}
+
+impl Reg {
+    pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
+        let dl = cx.data_layout();
+        match self.kind {
+            RegKind::Integer => match self.size.bits() {
+                1 => dl.i1_align.abi,
+                2..=8 => dl.i8_align.abi,
+                9..=16 => dl.i16_align.abi,
+                17..=32 => dl.i32_align.abi,
+                33..=64 => dl.i64_align.abi,
+                65..=128 => dl.i128_align.abi,
+                _ => panic!("unsupported integer: {self:?}"),
+            },
+            RegKind::Float => match self.size.bits() {
+                16 => dl.f16_align.abi,
+                32 => dl.f32_align.abi,
+                64 => dl.f64_align.abi,
+                128 => dl.f128_align.abi,
+                _ => panic!("unsupported float: {self:?}"),
+            },
+            RegKind::Vector => dl.vector_align(self.size).abi,
+        }
+    }
+}
diff --git a/compiler/rustc_abi/src/extern_abi/mod.rs b/compiler/rustc_abi/src/extern_abi.rs
index 130834d560f..130834d560f 100644
--- a/compiler/rustc_abi/src/extern_abi/mod.rs
+++ b/compiler/rustc_abi/src/extern_abi.rs
diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs
index d188750bfe1..221e990ae86 100644
--- a/compiler/rustc_abi/src/layout/ty.rs
+++ b/compiler/rustc_abi/src/layout/ty.rs
@@ -1,13 +1,15 @@
 use std::fmt;
 use std::ops::Deref;
 
-use Float::*;
-use Primitive::*;
 use rustc_data_structures::intern::Interned;
 use rustc_macros::HashStable_Generic;
 
+use crate::{
+    AbiAndPrefAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche,
+    PointeeInfo, Primitive, Scalar, Size, TargetDataLayout, Variants,
+};
+
 // Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
-use crate::{Float, *};
 
 rustc_index::newtype_index! {
     /// The *source-order* index of a field in a variant.
@@ -197,7 +199,9 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
         C: HasDataLayout,
     {
         match self.backend_repr {
-            BackendRepr::Scalar(scalar) => matches!(scalar.primitive(), Float(F32 | F64)),
+            BackendRepr::Scalar(scalar) => {
+                matches!(scalar.primitive(), Primitive::Float(Float::F32 | Float::F64))
+            }
             BackendRepr::Memory { .. } => {
                 if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
                     self.field(cx, 0).is_single_fp_element(cx)
diff --git a/compiler/rustc_borrowck/src/type_check/opaque_types.rs b/compiler/rustc_borrowck/src/type_check/opaque_types.rs
index ad4e006c21a..17482cc0cbd 100644
--- a/compiler/rustc_borrowck/src/type_check/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/type_check/opaque_types.rs
@@ -284,7 +284,7 @@ where
             return;
         }
 
-        match ty.kind() {
+        match *ty.kind() {
             ty::Closure(_, args) => {
                 // Skip lifetime parameters of the enclosing item(s)
 
@@ -316,10 +316,12 @@ where
                 args.as_coroutine().resume_ty().visit_with(self);
             }
 
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
-                // Skip lifetime parameters that are not captures.
-                let variances = self.tcx.variances_of(*def_id);
-
+            ty::Alias(kind, ty::AliasTy { def_id, args, .. })
+                if let Some(variances) = self.tcx.opt_alias_variances(kind, def_id) =>
+            {
+                // Skip lifetime parameters that are not captured, since they do
+                // not need member constraints registered for them; we'll erase
+                // them (and hopefully in the future replace them with placeholders).
                 for (v, s) in std::iter::zip(variances, args.iter()) {
                     if *v != ty::Bivariant {
                         s.visit_with(self);
diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs
index c9701fb9885..962f4b161d7 100644
--- a/compiler/rustc_codegen_gcc/src/base.rs
+++ b/compiler/rustc_codegen_gcc/src/base.rs
@@ -49,9 +49,7 @@ pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind {
         Linkage::LinkOnceODR => unimplemented!(),
         Linkage::WeakAny => unimplemented!(),
         Linkage::WeakODR => unimplemented!(),
-        Linkage::Appending => unimplemented!(),
         Linkage::Internal => GlobalKind::Internal,
-        Linkage::Private => GlobalKind::Internal,
         Linkage::ExternalWeak => GlobalKind::Imported, // TODO(antoyo): should be weak linkage.
         Linkage::Common => unimplemented!(),
     }
@@ -66,9 +64,7 @@ pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType {
         Linkage::LinkOnceODR => unimplemented!(),
         Linkage::WeakAny => FunctionType::Exported, // FIXME(antoyo): should be similar to linkonce.
         Linkage::WeakODR => unimplemented!(),
-        Linkage::Appending => unimplemented!(),
         Linkage::Internal => FunctionType::Internal,
-        Linkage::Private => FunctionType::Internal,
         Linkage::ExternalWeak => unimplemented!(),
         Linkage::Common => unimplemented!(),
     }
diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs
index 239902df7f0..a2df7b2596f 100644
--- a/compiler/rustc_codegen_gcc/src/mono_item.rs
+++ b/compiler/rustc_codegen_gcc/src/mono_item.rs
@@ -61,10 +61,7 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         // compiler-rt, then we want to implicitly compile everything with hidden
         // visibility as we're going to link this object all over the place but
         // don't want the symbols to get exported.
-        if linkage != Linkage::Internal
-            && linkage != Linkage::Private
-            && self.tcx.is_compiler_builtins(LOCAL_CRATE)
-        {
+        if linkage != Linkage::Internal && self.tcx.is_compiler_builtins(LOCAL_CRATE) {
             #[cfg(feature = "master")]
             decl.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
         } else {
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index d05faf5577b..d35c7945bae 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -157,9 +157,7 @@ pub(crate) fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage {
         Linkage::LinkOnceODR => llvm::Linkage::LinkOnceODRLinkage,
         Linkage::WeakAny => llvm::Linkage::WeakAnyLinkage,
         Linkage::WeakODR => llvm::Linkage::WeakODRLinkage,
-        Linkage::Appending => llvm::Linkage::AppendingLinkage,
         Linkage::Internal => llvm::Linkage::InternalLinkage,
-        Linkage::Private => llvm::Linkage::PrivateLinkage,
         Linkage::ExternalWeak => llvm::Linkage::ExternalWeakLinkage,
         Linkage::Common => llvm::Linkage::CommonLinkage,
     }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index f497ba95661..59c3fe635d0 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -319,19 +319,16 @@ fn build_subroutine_type_di_node<'ll, 'tcx>(
     // This is actually a function pointer, so wrap it in pointer DI.
     let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false);
     let (size, align) = match fn_ty.kind() {
-        ty::FnDef(..) => (0, 1),
-        ty::FnPtr(..) => (
-            cx.tcx.data_layout.pointer_size.bits(),
-            cx.tcx.data_layout.pointer_align.abi.bits() as u32,
-        ),
+        ty::FnDef(..) => (Size::ZERO, Align::ONE),
+        ty::FnPtr(..) => (cx.tcx.data_layout.pointer_size, cx.tcx.data_layout.pointer_align.abi),
         _ => unreachable!(),
     };
     let di_node = unsafe {
         llvm::LLVMRustDIBuilderCreatePointerType(
             DIB(cx),
             fn_di_node,
-            size,
-            align,
+            size.bits(),
+            align.bits() as u32,
             0, // Ignore DWARF address space.
             name.as_c_char_ptr(),
             name.len(),
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index a9737583037..19fb2754571 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -633,7 +633,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 true,
                 DIFlags::FlagZero,
                 argument_index,
-                align.bytes() as u32,
+                align.bits() as u32,
             )
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 0d04f770bc6..50a40c9c309 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -69,19 +69,6 @@ pub enum LLVMRustResult {
     Failure,
 }
 
-/// Translation of LLVM's MachineTypes enum, defined in llvm\include\llvm\BinaryFormat\COFF.h.
-///
-/// We include only architectures supported on Windows.
-#[derive(Copy, Clone, PartialEq)]
-#[repr(C)]
-pub enum LLVMMachineType {
-    AMD64 = 0x8664,
-    I386 = 0x14c,
-    ARM64 = 0xaa64,
-    ARM64EC = 0xa641,
-    ARM = 0x01c0,
-}
-
 /// Must match the layout of `LLVMRustModuleFlagMergeBehavior`.
 ///
 /// When merging modules (e.g. during LTO), their metadata flags are combined. Conflicts are
@@ -645,16 +632,6 @@ pub enum ThreadLocalMode {
     LocalExec,
 }
 
-/// LLVMRustTailCallKind
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum TailCallKind {
-    None,
-    Tail,
-    MustTail,
-    NoTail,
-}
-
 /// LLVMRustChecksumKind
 #[derive(Copy, Clone)]
 #[repr(C)]
@@ -773,7 +750,6 @@ pub struct Builder<'a>(InvariantOpaque<'a>);
 #[repr(C)]
 pub struct PassManager<'a>(InvariantOpaque<'a>);
 unsafe extern "C" {
-    pub type Pass;
     pub type TargetMachine;
     pub type Archive;
 }
@@ -799,7 +775,6 @@ unsafe extern "C" {
 }
 
 pub type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
-pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
 
 pub mod debuginfo {
     use std::ptr;
@@ -853,7 +828,6 @@ pub mod debuginfo {
     pub type DIFile = DIScope;
     pub type DILexicalBlock = DIScope;
     pub type DISubprogram = DIScope;
-    pub type DINameSpace = DIScope;
     pub type DIType = DIDescriptor;
     pub type DIBasicType = DIType;
     pub type DIDerivedType = DIType;
@@ -1809,7 +1783,6 @@ unsafe extern "C" {
         Name: *const c_char,
         NameLen: size_t,
     ) -> Option<&Value>;
-    pub fn LLVMRustSetTailCallKind(CallInst: &Value, TKC: TailCallKind);
 
     // Operations on attributes
     pub fn LLVMRustCreateAttrNoValue(C: &Context, attr: AttributeKind) -> &Attribute;
@@ -2586,8 +2559,6 @@ unsafe extern "C" {
 
     pub fn LLVMRustGetElementTypeArgIndex(CallSite: &Value) -> i32;
 
-    pub fn LLVMRustIsBitcode(ptr: *const u8, len: usize) -> bool;
-
     pub fn LLVMRustLLVMHasZlibCompressionForDebugSymbols() -> bool;
 
     pub fn LLVMRustLLVMHasZstdCompressionForDebugSymbols() -> bool;
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 33789c6261f..70edee21bd6 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -71,10 +71,7 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
         // compiler-rt, then we want to implicitly compile everything with hidden
         // visibility as we're going to link this object all over the place but
         // don't want the symbols to get exported.
-        if linkage != Linkage::Internal
-            && linkage != Linkage::Private
-            && self.tcx.is_compiler_builtins(LOCAL_CRATE)
-        {
+        if linkage != Linkage::Internal && self.tcx.is_compiler_builtins(LOCAL_CRATE) {
             llvm::set_visibility(lldecl, llvm::Visibility::Hidden);
         } else {
             llvm::set_visibility(lldecl, base::visibility_to_llvm(visibility));
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 4166387dad0..7acdbd19993 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -41,7 +41,6 @@ fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
     // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
     // and don't have to be, LLVM treats them as no-ops.
     match name {
-        "appending" => Appending,
         "available_externally" => AvailableExternally,
         "common" => Common,
         "extern_weak" => ExternalWeak,
@@ -49,7 +48,6 @@ fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
         "internal" => Internal,
         "linkonce" => LinkOnceAny,
         "linkonce_odr" => LinkOnceODR,
-        "private" => Private,
         "weak" => WeakAny,
         "weak_odr" => WeakODR,
         _ => tcx.dcx().span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 4be363ca9a2..2eecf81a5d2 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1708,15 +1708,32 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             let mut cs_bx = Bx::build(self.cx, llbb);
             let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
 
-            // The "null" here is actually a RTTI type descriptor for the
-            // C++ personality function, but `catch (...)` has no type so
-            // it's null. The 64 here is actually a bitfield which
-            // represents that this is a catch-all block.
             bx = Bx::build(self.cx, cp_llbb);
             let null =
                 bx.const_null(bx.type_ptr_ext(bx.cx().data_layout().instruction_address_space));
-            let sixty_four = bx.const_i32(64);
-            funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null]));
+
+            // The `null` in first argument here is actually a RTTI type
+            // descriptor for the C++ personality function, but `catch (...)`
+            // has no type so it's null.
+            let args = if base::wants_msvc_seh(self.cx.sess()) {
+                // This bitmask is a single `HT_IsStdDotDot` flag, which
+                // represents that this is a C++-style `catch (...)` block that
+                // only captures programmatic exceptions, not all SEH
+                // exceptions. The second `null` points to a non-existent
+                // `alloca` instruction, which an LLVM pass would inline into
+                // the initial SEH frame allocation.
+                let adjectives = bx.const_i32(0x40);
+                &[null, adjectives, null] as &[_]
+            } else {
+                // Specifying more arguments than necessary usually doesn't
+                // hurt, but the `WasmEHPrepare` LLVM pass does not recognize
+                // anything other than a single `null` as a `catch (...)` block,
+                // leading to problems down the line during instruction
+                // selection.
+                &[null] as &[_]
+            };
+
+            funclet = Some(bx.catch_pad(cs, args));
         } else {
             llbb = Bx::append_block(self.cx, self.llfn, "terminate");
             bx = Bx::build(self.cx, llbb);
diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
index dc406809874..eb0711dbb32 100644
--- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
@@ -187,10 +187,9 @@ fn prefix_and_suffix<'tcx>(
                     }
                 }
             }
-            Linkage::Internal | Linkage::Private => {
+            Linkage::Internal => {
                 // write nothing
             }
-            Linkage::Appending => emit_fatal("Only global variables can have appending linkage!"),
             Linkage::Common => emit_fatal("Functions may not have common linkage"),
             Linkage::AvailableExternally => {
                 // this would make the function equal an extern definition
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 217a7aeb2d7..822cf4982b5 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -9,7 +9,7 @@ macro_rules! declare_features {
         $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr),
     )+) => {
         /// Formerly unstable features that have now been accepted (stabilized).
-        pub const ACCEPTED_LANG_FEATURES: &[Feature] = &[
+        pub static ACCEPTED_LANG_FEATURES: &[Feature] = &[
             $(Feature {
                 name: sym::$feature,
                 since: $ver,
@@ -400,6 +400,9 @@ declare_features! (
     /// Allows `#[track_caller]` to be used which provides
     /// accurate caller location reporting during panic (RFC 2091).
     (accepted, track_caller, "1.46.0", Some(47809)),
+    /// Allows dyn upcasting trait objects via supertraits.
+    /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
+    (accepted, trait_upcasting, "CURRENT_RUSTC_VERSION", Some(65991)),
     /// Allows #[repr(transparent)] on univariant enums (RFC 2645).
     (accepted, transparent_enums, "1.42.0", Some(60405)),
     /// Allows indexing tuples.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 67eb96e4d56..eb5fac96af2 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -318,7 +318,7 @@ pub struct BuiltinAttribute {
 
 /// Attributes that have a special meaning to rustc or rustdoc.
 #[rustfmt::skip]
-pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
+pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // ==========================================================================
     // Stable attributes:
     // ==========================================================================
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 081638715df..2fb0c8e4344 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -14,7 +14,7 @@ macro_rules! declare_features {
         $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, $reason:expr),
     )+) => {
         /// Formerly unstable features that have now been removed.
-        pub const REMOVED_LANG_FEATURES: &[RemovedFeature] = &[
+        pub static REMOVED_LANG_FEATURES: &[RemovedFeature] = &[
             $(RemovedFeature {
                 feature: Feature {
                     name: sym::$feature,
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 115b3eabbaa..3a2e810dc6a 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -104,7 +104,7 @@ macro_rules! declare_features {
     )+) => {
         /// Unstable language features that are being implemented or being
         /// considered for acceptance (stabilization) or removal.
-        pub const UNSTABLE_LANG_FEATURES: &[Feature] = &[
+        pub static UNSTABLE_LANG_FEATURES: &[Feature] = &[
             $(Feature {
                 name: sym::$feature,
                 since: $ver,
@@ -634,9 +634,6 @@ declare_features! (
     (unstable, thread_local, "1.0.0", Some(29594)),
     /// Allows defining `trait X = A + B;` alias items.
     (unstable, trait_alias, "1.24.0", Some(41517)),
-    /// Allows dyn upcasting trait objects via supertraits.
-    /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
-    (unstable, trait_upcasting, "1.56.0", Some(65991)),
     /// Allows for transmuting between arrays with sizes that contain generic consts.
     (unstable, transmute_generic_consts, "1.70.0", Some(109929)),
     /// Allows #[repr(transparent)] on unions (RFC 2645).
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 8efef0c612b..fb1df518a88 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -325,6 +325,10 @@ pub fn expr_to_string(ann: &dyn PpAnn, pat: &hir::Expr<'_>) -> String {
     to_string(ann, |s| s.print_expr(pat))
 }
 
+pub fn item_to_string(ann: &dyn PpAnn, pat: &hir::Item<'_>) -> String {
+    to_string(ann, |s| s.print_item(pat))
+}
+
 impl<'a> State<'a> {
     fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
         self.maybe_print_comment(span.hi());
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 83acc7dd6af..56cc9b6d551 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -605,7 +605,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         )];
 
         let mut has_unsized_tuple_coercion = false;
-        let mut has_trait_upcasting_coercion = None;
 
         // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
         // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@@ -690,13 +689,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                     // these here and emit a feature error if coercion doesn't fail
                     // due to another reason.
                     match impl_source {
-                        traits::ImplSource::Builtin(
-                            BuiltinImplSource::TraitUpcasting { .. },
-                            _,
-                        ) => {
-                            has_trait_upcasting_coercion =
-                                Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1)));
-                        }
                         traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
                             has_unsized_tuple_coercion = true;
                         }
@@ -707,21 +699,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             }
         }
 
-        if let Some((sub, sup)) = has_trait_upcasting_coercion
-            && !self.tcx().features().trait_upcasting()
-        {
-            // Renders better when we erase regions, since they're not really the point here.
-            let (sub, sup) = self.tcx.erase_regions((sub, sup));
-            let mut err = feature_err(
-                &self.tcx.sess,
-                sym::trait_upcasting,
-                self.cause.span,
-                format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"),
-            );
-            err.note(format!("required when coercing `{source}` into `{target}`"));
-            err.emit();
-        }
-
         if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion() {
             feature_err(
                 &self.tcx.sess,
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 1f3f03b9929..4618c5d3849 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -651,6 +651,7 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
         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)
+            && inf_span.can_be_used_for_suggestions()
         {
             return ControlFlow::Break(errors::SuggestAnnotation::Unit(inf_span));
         }
@@ -662,7 +663,7 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
         &mut self,
         qpath: &'tcx rustc_hir::QPath<'tcx>,
         id: HirId,
-        _span: Span,
+        span: Span,
     ) -> Self::Result {
         let arg_segment = match qpath {
             hir::QPath::Resolved(_, path) => {
@@ -674,13 +675,21 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
             }
         };
         // Alternatively, try to turbofish `::<_, (), _>`.
-        if let Some(def_id) = self.fcx.typeck_results.borrow().qpath_res(qpath, id).opt_def_id() {
+        if let Some(def_id) = self.fcx.typeck_results.borrow().qpath_res(qpath, id).opt_def_id()
+            && span.can_be_used_for_suggestions()
+        {
             self.suggest_for_segment(arg_segment, def_id, id)?;
         }
         hir::intravisit::walk_qpath(self, qpath, id)
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result {
+        if let hir::ExprKind::Closure(&hir::Closure { body, .. })
+        | hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) = expr.kind
+        {
+            self.visit_body(self.fcx.tcx.hir().body(body))?;
+        }
+
         // Try to suggest adding an explicit qself `()` to a trait method path.
         // i.e. changing `Default::default()` to `<() as Default>::default()`.
         if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
@@ -691,17 +700,21 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
             && let Some(vid) = self.fcx.root_vid(self_ty)
             && self.reachable_vids.contains(&vid)
             && let [.., trait_segment, _method_segment] = path.segments
+            && expr.span.can_be_used_for_suggestions()
         {
             let span = path.span.shrink_to_lo().to(trait_segment.ident.span);
             return ControlFlow::Break(errors::SuggestAnnotation::Path(span));
         }
+
         // Or else, try suggesting turbofishing the method args.
         if let hir::ExprKind::MethodCall(segment, ..) = expr.kind
             && let Some(def_id) =
                 self.fcx.typeck_results.borrow().type_dependent_def_id(expr.hir_id)
+            && expr.span.can_be_used_for_suggestions()
         {
             self.suggest_for_segment(segment, def_id, expr.hir_id)?;
         }
+
         hir::intravisit::walk_expr(self, expr)
     }
 
@@ -712,6 +725,7 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
             && let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(local.hir_id)
             && let Some(vid) = self.fcx.root_vid(ty)
             && self.reachable_vids.contains(&vid)
+            && local.span.can_be_used_for_suggestions()
         {
             return ControlFlow::Break(errors::SuggestAnnotation::Local(
                 local.pat.span.shrink_to_hi(),
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 5ce9e0556b4..77081548d11 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -2641,8 +2641,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     /// Returns the parameters of a function, with their generic parameters if those are the full
-    /// type of that parameter. Returns `None` if the function has no generics or the body is
-    /// unavailable (eg is an instrinsic).
+    /// type of that parameter.
+    ///
+    /// Returns `None` if the body is not a named function (e.g. a closure).
     fn get_hir_param_info(
         &self,
         def_id: DefId,
@@ -2667,6 +2668,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 kind: hir::ItemKind::Fn { sig, generics, body, .. },
                 ..
             }) => (sig, generics, Some(body), None),
+            hir::Node::ForeignItem(&hir::ForeignItem {
+                kind: hir::ForeignItemKind::Fn(sig, params, generics),
+                ..
+            }) => (sig, generics, None, Some(params)),
             _ => return None,
         };
 
@@ -2700,7 +2705,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ))
             }
             (None, Some(params)) => {
-                let params = params.get(is_method as usize..)?;
+                let params =
+                    params.get(is_method as usize..params.len() - sig.decl.c_variadic as usize)?;
                 debug_assert_eq!(params.len(), fn_inputs.len());
                 Some((
                     fn_inputs.zip(params.iter().map(|param| FnParam::Name(param))).collect(),
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 5c1c38aeb95..3e48e8d15c3 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -347,9 +347,17 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // yield an object-type (e.g., `&Object` or `Box<Object>`
         // etc).
 
-        // FIXME: this feels, like, super dubious
-        self.fcx
-            .autoderef(self.span, self_ty)
+        let mut autoderef = self.fcx.autoderef(self.span, self_ty);
+
+        // We don't need to gate this behind arbitrary self types
+        // per se, but it does make things a bit more gated.
+        if self.tcx.features().arbitrary_self_types()
+            || self.tcx.features().arbitrary_self_types_pointers()
+        {
+            autoderef = autoderef.use_receiver_trait();
+        }
+
+        autoderef
             .include_raw_pointers()
             .find_map(|(ty, _)| match ty.kind() {
                 ty::Dynamic(data, ..) => Some(closure(
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 2e7415cec5d..7c2a2b3fdf7 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -812,7 +812,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Determine the binding mode...
         let bm = match user_bind_annot {
-            BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
+            BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(def_br_mutbl) = def_br => {
                 // Only mention the experimental `mut_ref` feature if if we're in edition 2024 and
                 // using other experimental matching features compatible with it.
                 if pat.span.at_least_rust_2024()
@@ -834,22 +834,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // `mut` resets the binding mode on edition <= 2021
                     self.add_rust_2024_migration_desugared_pat(
                         pat_info.top_info.hir_id,
-                        pat.span,
+                        pat,
                         ident.span,
-                        "requires binding by-value, but the implicit default is by-reference",
+                        def_br_mutbl,
                     );
                     BindingMode(ByRef::No, Mutability::Mut)
                 }
             }
             BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
             BindingMode(ByRef::Yes(_), _) => {
-                if matches!(def_br, ByRef::Yes(_)) {
+                if let ByRef::Yes(def_br_mutbl) = def_br {
                     // `ref`/`ref mut` overrides the binding mode on edition <= 2021
                     self.add_rust_2024_migration_desugared_pat(
                         pat_info.top_info.hir_id,
-                        pat.span,
+                        pat,
                         ident.span,
-                        "cannot override to bind by-reference when that is the implicit default",
+                        def_br_mutbl,
                     );
                 }
                 user_bind_annot
@@ -2386,9 +2386,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     pat_info.binding_mode = ByRef::No;
                     self.add_rust_2024_migration_desugared_pat(
                         pat_info.top_info.hir_id,
-                        pat.span,
+                        pat,
                         inner.span,
-                        "cannot implicitly match against multiple layers of reference",
+                        inh_mut,
                     )
                 }
             }
@@ -2778,33 +2778,65 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn add_rust_2024_migration_desugared_pat(
         &self,
         pat_id: HirId,
-        subpat_span: Span,
+        subpat: &'tcx Pat<'tcx>,
         cutoff_span: Span,
-        detailed_label: &str,
+        def_br_mutbl: Mutability,
     ) {
         // Try to trim the span we're labeling to just the `&` or binding mode that's an issue.
         // If the subpattern's span is is from an expansion, the emitted label will not be trimmed.
         let source_map = self.tcx.sess.source_map();
         let cutoff_span = source_map
-            .span_extend_prev_while(cutoff_span, char::is_whitespace)
+            .span_extend_prev_while(cutoff_span, |c| c.is_whitespace() || c == '(')
             .unwrap_or(cutoff_span);
-        // Ensure we use the syntax context and thus edition of `subpat_span`; this will be a hard
+        // Ensure we use the syntax context and thus edition of `subpat.span`; this will be a hard
         // error if the subpattern is of edition >= 2024.
-        let trimmed_span = subpat_span.until(cutoff_span).with_ctxt(subpat_span.ctxt());
+        let trimmed_span = subpat.span.until(cutoff_span).with_ctxt(subpat.span.ctxt());
+
+        let mut typeck_results = self.typeck_results.borrow_mut();
+        let mut table = typeck_results.rust_2024_migration_desugared_pats_mut();
+        // FIXME(ref_pat_eat_one_layer_2024): The migration diagnostic doesn't know how to track the
+        // default binding mode in the presence of Rule 3 or Rule 5. As a consequence, the labels it
+        // gives for default binding modes are wrong, as well as suggestions based on the default
+        // binding mode. This keeps it from making those suggestions, as doing so could panic.
+        let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo {
+            primary_labels: Vec::new(),
+            bad_modifiers: false,
+            bad_ref_pats: false,
+            suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024()
+                && !self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
+        });
 
         // Only provide a detailed label if the problematic subpattern isn't from an expansion.
         // In the case that it's from a macro, we'll add a more detailed note in the emitter.
-        let desc = if subpat_span.from_expansion() {
-            "default binding mode is reset within expansion"
+        let from_expansion = subpat.span.from_expansion();
+        let primary_label = if from_expansion {
+            // NB: This wording assumes the only expansions that can produce problematic reference
+            // patterns and bindings are macros. If a desugaring or AST pass is added that can do
+            // so, we may want to inspect the span's source callee or macro backtrace.
+            "occurs within macro expansion".to_owned()
         } else {
-            detailed_label
+            let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
+                info.bad_modifiers |= true;
+                // If the user-provided binding modifier doesn't match the default binding mode, we'll
+                // need to suggest reference patterns, which can affect other bindings.
+                // For simplicity, we opt to suggest making the pattern fully explicit.
+                info.suggest_eliding_modes &=
+                    user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
+                "binding modifier"
+            } else {
+                info.bad_ref_pats |= true;
+                // For simplicity, we don't try to suggest eliding reference patterns. Thus, we'll
+                // suggest adding them instead, which can affect the types assigned to bindings.
+                // As such, we opt to suggest making the pattern fully explicit.
+                info.suggest_eliding_modes = false;
+                "reference pattern"
+            };
+            let dbm_str = match def_br_mutbl {
+                Mutability::Not => "ref",
+                Mutability::Mut => "ref mut",
+            };
+            format!("{pat_kind} not allowed under `{dbm_str}` default binding mode")
         };
-
-        self.typeck_results
-            .borrow_mut()
-            .rust_2024_migration_desugared_pats_mut()
-            .entry(pat_id)
-            .or_default()
-            .push((trimmed_span, desc.to_owned()));
+        info.primary_labels.push((trimmed_span, primary_label));
     }
 }
diff --git a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs
index c02ab98b2ba..379410641fe 100644
--- a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs
+++ b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs
@@ -48,7 +48,7 @@ where
             return ty.super_visit_with(self);
         }
 
-        match ty.kind() {
+        match *ty.kind() {
             // We can prove that an alias is live two ways:
             // 1. All the components are live.
             //
@@ -95,11 +95,9 @@ where
                     assert!(r.type_flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS));
                     r.visit_with(self);
                 } else {
-                    // Skip lifetime parameters that are not captures.
-                    let variances = match kind {
-                        ty::Opaque => Some(self.tcx.variances_of(*def_id)),
-                        _ => None,
-                    };
+                    // Skip lifetime parameters that are not captured, since they do
+                    // not need to be live.
+                    let variances = tcx.opt_alias_variances(kind, def_id);
 
                     for (idx, s) in args.iter().enumerate() {
                         if variances.map(|variances| variances[idx]) != Some(ty::Bivariant) {
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 84e51b18dc5..86a47426049 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -392,13 +392,13 @@ where
         // the problem is to add `T: 'r`, which isn't true. So, if there are no
         // inference variables, we use a verify constraint instead of adding
         // edges, which winds up enforcing the same condition.
-        let is_opaque = alias_ty.kind(self.tcx) == ty::Opaque;
+        let kind = alias_ty.kind(self.tcx);
         if approx_env_bounds.is_empty()
             && trait_bounds.is_empty()
-            && (alias_ty.has_infer_regions() || is_opaque)
+            && (alias_ty.has_infer_regions() || kind == ty::Opaque)
         {
             debug!("no declared bounds");
-            let opt_variances = is_opaque.then(|| self.tcx.variances_of(alias_ty.def_id));
+            let opt_variances = self.tcx.opt_alias_variances(kind, alias_ty.def_id);
             self.args_must_outlive(alias_ty.args, origin, region, opt_variances);
             return;
         }
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index d68f3639176..c14c288c6e4 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -102,12 +102,11 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
 
     #[instrument(level = "debug", skip(self))]
     pub(crate) fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tcx> {
-        let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
-
         // Search the env for where clauses like `P: 'a`.
         let env_bounds = self.approx_declared_bounds_from_env(alias_ty).into_iter().map(|binder| {
             if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars()
-                && ty == alias_ty_as_ty
+                && let ty::Alias(_, alias_ty_from_bound) = *ty.kind()
+                && alias_ty_from_bound == alias_ty
             {
                 // Micro-optimize if this is an exact match (this
                 // occurs often when there are no region variables
@@ -127,7 +126,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         // see the extensive comment in projection_must_outlive
         let recursive_bound = {
             let mut components = smallvec![];
-            compute_alias_components_recursive(self.tcx, alias_ty_as_ty, &mut components);
+            let kind = alias_ty.kind(self.tcx);
+            compute_alias_components_recursive(self.tcx, kind, alias_ty, &mut components);
             self.bound_from_components(&components)
         };
 
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index eda9c4e03fe..e5adcdb244f 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -827,7 +827,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
     if tcx.sess.opts.unstable_opts.input_stats {
         rustc_passes::input_stats::print_hir_stats(tcx);
     }
-    #[cfg(debug_assertions)]
+    // When using rustdoc's "jump to def" feature, it enters this code and `check_crate`
+    // is not defined. So we need to cfg it out.
+    #[cfg(all(not(doc), debug_assertions))]
     rustc_passes::hir_id_validator::check_crate(tcx);
     let sess = tcx.sess;
     sess.time("misc_checking_1", || {
diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
index 657642e093c..181f44fb4de 100644
--- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
+++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
@@ -1,6 +1,5 @@
 use rustc_hir::{self as hir, LangItem};
 use rustc_middle::ty;
-use rustc_session::lint::FutureIncompatibilityReason;
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::sym;
 use rustc_trait_selection::traits::supertraits;
@@ -9,11 +8,12 @@ use crate::lints::{SupertraitAsDerefTarget, SupertraitAsDerefTargetLabel};
 use crate::{LateContext, LateLintPass, LintContext};
 
 declare_lint! {
-    /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
-    /// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
+    /// The `deref_into_dyn_supertrait` lint is emitted whenever there is a `Deref` implementation
+    /// for `dyn SubTrait` with a `dyn SuperTrait` type as the `Output` type.
     ///
-    /// These implementations will become shadowed when the `trait_upcasting` feature is stabilized.
-    /// The `deref` functions will no longer be called implicitly, so there might be behavior change.
+    /// These implementations are "shadowed" by trait upcasting (stabilized since
+    /// CURRENT_RUSTC_VERSION). The `deref` functions is no longer called implicitly, which might
+    /// change behavior compared to previous rustc versions.
     ///
     /// ### Example
     ///
@@ -43,15 +43,14 @@ declare_lint! {
     ///
     /// ### Explanation
     ///
-    /// The dyn upcasting coercion feature adds new coercion rules, taking priority
-    /// over certain other coercion rules, which will cause some behavior change.
+    /// The trait upcasting coercion added a new coercion rule, taking priority over certain other
+    /// coercion rules, which causes some behavior change compared to older `rustc` versions.
+    ///
+    /// `deref` can be still called explicitly, it just isn't called as part of a deref coercion
+    /// (since trait upcasting coercion takes priority).
     pub DEREF_INTO_DYN_SUPERTRAIT,
-    Warn,
-    "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
-        reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
-    };
+    Allow,
+    "`Deref` implementation with a supertrait trait object for output is shadowed by trait upcasting",
 }
 
 declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]);
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index bc7cd3d118c..723b894c43b 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -246,6 +246,14 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast>
                 }
             }
             ast_visit::walk_assoc_item(cx, item, ctxt);
+            match ctxt {
+                ast_visit::AssocCtxt::Trait => {
+                    lint_callback!(cx, check_trait_item_post, item);
+                }
+                ast_visit::AssocCtxt::Impl => {
+                    lint_callback!(cx, check_impl_item_post, item);
+                }
+            }
         });
     }
 
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index fd6c17735c5..3e97f4c86ba 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -21,6 +21,7 @@
 
 // tidy-alphabetical-start
 #![allow(internal_features)]
+#![cfg_attr(bootstrap, feature(trait_upcasting))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(array_windows)]
@@ -32,7 +33,6 @@
 #![feature(let_chains)]
 #![feature(rustc_attrs)]
 #![feature(rustdoc_internals)]
-#![feature(trait_upcasting)]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
 
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index 77bd13aacf7..409a23d1da0 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -162,7 +162,9 @@ macro_rules! early_lint_methods {
                 c: rustc_span::Span,
                 d_: rustc_ast::NodeId);
             fn check_trait_item(a: &rustc_ast::AssocItem);
+            fn check_trait_item_post(a: &rustc_ast::AssocItem);
             fn check_impl_item(a: &rustc_ast::AssocItem);
+            fn check_impl_item_post(a: &rustc_ast::AssocItem);
             fn check_variant(a: &rustc_ast::Variant);
             fn check_attribute(a: &rustc_ast::Attribute);
             fn check_attributes(a: &[rustc_ast::Attribute]);
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 76ad7fc8909..b8cef6a7e25 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -195,33 +195,6 @@ LLVMRustVerifyFunction(LLVMValueRef Fn, LLVMRustVerifierFailureAction Action) {
   return LLVMVerifyFunction(Fn, fromRust(Action));
 }
 
-enum class LLVMRustTailCallKind {
-  None,
-  Tail,
-  MustTail,
-  NoTail,
-};
-
-static CallInst::TailCallKind fromRust(LLVMRustTailCallKind Kind) {
-  switch (Kind) {
-  case LLVMRustTailCallKind::None:
-    return CallInst::TailCallKind::TCK_None;
-  case LLVMRustTailCallKind::Tail:
-    return CallInst::TailCallKind::TCK_Tail;
-  case LLVMRustTailCallKind::MustTail:
-    return CallInst::TailCallKind::TCK_MustTail;
-  case LLVMRustTailCallKind::NoTail:
-    return CallInst::TailCallKind::TCK_NoTail;
-  default:
-    report_fatal_error("bad CallInst::TailCallKind.");
-  }
-}
-
-extern "C" void LLVMRustSetTailCallKind(LLVMValueRef Call,
-                                        LLVMRustTailCallKind TCK) {
-  unwrap<CallInst>(Call)->setTailCallKind(fromRust(TCK));
-}
-
 extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M,
                                                     const char *Name,
                                                     size_t NameLen,
@@ -1976,10 +1949,6 @@ extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) {
   return -1;
 }
 
-extern "C" bool LLVMRustIsBitcode(char *ptr, size_t len) {
-  return identify_magic(StringRef(ptr, len)) == file_magic::bitcode;
-}
-
 extern "C" bool LLVMRustIsNonGVFunctionPointerTy(LLVMValueRef V) {
   if (unwrap<Value>(V)->getType()->isPointerTy()) {
     if (auto *GV = dyn_cast<GlobalValue>(unwrap<Value>(V))) {
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 7a6d329fd47..95128a5d903 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -29,6 +29,7 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::potential_query_instability)]
 #![allow(rustc::untranslatable_diagnostic)]
+#![cfg_attr(bootstrap, feature(trait_upcasting))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(allocator_api)]
@@ -56,7 +57,6 @@
 #![feature(ptr_alignment_type)]
 #![feature(rustc_attrs)]
 #![feature(rustdoc_internals)]
-#![feature(trait_upcasting)]
 #![feature(trusted_len)]
 #![feature(try_blocks)]
 #![feature(try_trait_v2)]
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 1784665bcae..311bc60c3cd 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -178,7 +178,7 @@ impl CodegenFnAttrs {
             || match self.linkage {
                 // These are private, so make sure we don't try to consider
                 // them external.
-                None | Some(Linkage::Internal | Linkage::Private) => false,
+                None | Some(Linkage::Internal) => false,
                 Some(_) => true,
             }
     }
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 75931956310..d4a9aac3733 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -327,9 +327,7 @@ pub enum Linkage {
     LinkOnceODR,
     WeakAny,
     WeakODR,
-    Appending,
     Internal,
-    Private,
     ExternalWeak,
     Common,
 }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index c6fc5f98f56..82b4fe193f0 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -194,6 +194,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.variances_of(def_id)
     }
 
+    fn opt_alias_variances(
+        self,
+        kind: impl Into<ty::AliasTermKind>,
+        def_id: DefId,
+    ) -> Option<&'tcx [ty::Variance]> {
+        self.opt_alias_variances(kind, def_id)
+    }
+
     fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
         self.type_of(def_id)
     }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 88eea6101b5..6fe1502c66d 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -94,7 +94,7 @@ pub use self::sty::{
 pub use self::trait_def::TraitDef;
 pub use self::typeck_results::{
     CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity,
-    TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind,
+    Rust2024IncompatiblePatInfo, TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind,
 };
 pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
 use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 3c6ed997845..49bdb5e9dc3 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -73,9 +73,9 @@ pub struct TypeckResults<'tcx> {
     /// Stores the actual binding mode for all instances of [`BindingMode`].
     pat_binding_modes: ItemLocalMap<BindingMode>,
 
-    /// Top-level patterns whose match ergonomics need to be desugared by the Rust 2021 -> 2024
-    /// migration lint. Problematic subpatterns are stored in the `Vec` for the lint to highlight.
-    rust_2024_migration_desugared_pats: ItemLocalMap<Vec<(Span, String)>>,
+    /// Top-level patterns incompatible with Rust 2024's match ergonomics. These will be translated
+    /// to a form valid in all Editions, either as a lint diagnostic or hard error.
+    rust_2024_migration_desugared_pats: ItemLocalMap<Rust2024IncompatiblePatInfo>,
 
     /// Stores the types which were implicitly dereferenced in pattern binding modes
     /// for later usage in THIR lowering. For example,
@@ -420,7 +420,7 @@ impl<'tcx> TypeckResults<'tcx> {
 
     pub fn rust_2024_migration_desugared_pats(
         &self,
-    ) -> LocalTableInContext<'_, Vec<(Span, String)>> {
+    ) -> LocalTableInContext<'_, Rust2024IncompatiblePatInfo> {
         LocalTableInContext {
             hir_owner: self.hir_owner,
             data: &self.rust_2024_migration_desugared_pats,
@@ -429,7 +429,7 @@ impl<'tcx> TypeckResults<'tcx> {
 
     pub fn rust_2024_migration_desugared_pats_mut(
         &mut self,
-    ) -> LocalTableInContextMut<'_, Vec<(Span, String)>> {
+    ) -> LocalTableInContextMut<'_, Rust2024IncompatiblePatInfo> {
         LocalTableInContextMut {
             hir_owner: self.hir_owner,
             data: &mut self.rust_2024_migration_desugared_pats,
@@ -811,3 +811,17 @@ impl<'tcx> std::fmt::Display for UserTypeKind<'tcx> {
         }
     }
 }
+
+/// Information on a pattern incompatible with Rust 2024, for use by the error/migration diagnostic
+/// emitted during THIR construction.
+#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
+pub struct Rust2024IncompatiblePatInfo {
+    /// Labeled spans for `&`s, `&mut`s, and binding modifiers incompatible with Rust 2024.
+    pub primary_labels: Vec<(Span, String)>,
+    /// Whether any binding modifiers occur under a non-`move` default binding mode.
+    pub bad_modifiers: bool,
+    /// Whether any `&` or `&mut` patterns occur under a non-`move` default binding mode.
+    pub bad_ref_pats: bool,
+    /// If `true`, we can give a simpler suggestion solely by eliding explicit binding modifiers.
+    pub suggest_eliding_modes: bool,
+}
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 6fd0fb9a0a4..398ed57faeb 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -948,6 +948,29 @@ impl<'tcx> TyCtxt<'tcx> {
 
         ty
     }
+
+    // Computes the variances for an alias (opaque or RPITIT) that represent
+    // its (un)captured regions.
+    pub fn opt_alias_variances(
+        self,
+        kind: impl Into<ty::AliasTermKind>,
+        def_id: DefId,
+    ) -> Option<&'tcx [ty::Variance]> {
+        match kind.into() {
+            ty::AliasTermKind::ProjectionTy => {
+                if self.is_impl_trait_in_trait(def_id) {
+                    Some(self.variances_of(def_id))
+                } else {
+                    None
+                }
+            }
+            ty::AliasTermKind::OpaqueTy => Some(self.variances_of(def_id)),
+            ty::AliasTermKind::InherentTy
+            | ty::AliasTermKind::WeakTy
+            | ty::AliasTermKind::UnevaluatedConst
+            | ty::AliasTermKind::ProjectionConst => None,
+        }
+    }
 }
 
 struct OpaqueTypeExpander<'tcx> {
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 3cf3c332893..fae159103e7 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -285,7 +285,16 @@ mir_build_pointer_pattern = function pointers and raw pointers not derived from
 
 mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
 
-mir_build_rust_2024_incompatible_pat = this pattern relies on behavior which may change in edition 2024
+mir_build_rust_2024_incompatible_pat = {$bad_modifiers ->
+        *[true] binding modifiers{$bad_ref_pats ->
+            *[true] {" "}and reference patterns
+            [false] {""}
+        }
+        [false] reference patterns
+    } may only be written when the default binding mode is `move`{$is_hard_error ->
+        *[true] {""}
+        [false] {" "}in Rust 2024
+    }
 
 mir_build_static_in_pattern = statics cannot be referenced in patterns
     .label = can't be used in patterns
diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs
index 921205428db..18db8c1debb 100644
--- a/compiler/rustc_mir_build/src/check_tail_calls.rs
+++ b/compiler/rustc_mir_build/src/check_tail_calls.rs
@@ -132,11 +132,24 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
         }
 
         {
+            // `#[track_caller]` affects the ABI of a function (by adding a location argument),
+            // so a `track_caller` can only tail call other `track_caller` functions.
+            //
+            // The issue is however that we can't know if a function is `track_caller` or not at
+            // this point (THIR can be polymorphic, we may have an unresolved trait function).
+            // We could only allow functions that we *can* resolve and *are* `track_caller`,
+            // but that would turn changing `track_caller`-ness into a breaking change,
+            // which is probably undesirable.
+            //
+            // Also note that we don't check callee's `track_caller`-ness at all, mostly for the
+            // reasons above, but also because we can always tailcall the shim we'd generate for
+            // coercing the function to an `fn()` pointer. (although in that case the tailcall is
+            // basically useless -- the shim calls the actual function, so tailcalling the shim is
+            // equivalent to calling the function)
             let caller_needs_location = self.needs_location(self.caller_ty);
-            let callee_needs_location = self.needs_location(ty);
 
-            if caller_needs_location != callee_needs_location {
-                self.report_track_caller_mismatch(expr.span, caller_needs_location);
+            if caller_needs_location {
+                self.report_track_caller_caller(expr.span);
             }
         }
 
@@ -150,7 +163,9 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
     }
 
     /// Returns true if function of type `ty` needs location argument
-    /// (i.e. if a function is marked as `#[track_caller]`)
+    /// (i.e. if a function is marked as `#[track_caller]`).
+    ///
+    /// Panics if the function's instance can't be immediately resolved.
     fn needs_location(&self, ty: Ty<'tcx>) -> bool {
         if let &ty::FnDef(did, substs) = ty.kind() {
             let instance =
@@ -293,25 +308,15 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
         self.found_errors = Err(err);
     }
 
-    fn report_track_caller_mismatch(&mut self, sp: Span, caller_needs_location: bool) {
-        let err = match caller_needs_location {
-            true => self
-                .tcx
-                .dcx()
-                .struct_span_err(
-                    sp,
-                    "a function marked with `#[track_caller]` cannot tail-call one that is not",
-                )
-                .emit(),
-            false => self
-                .tcx
-                .dcx()
-                .struct_span_err(
-                    sp,
-                    "a function mot marked with `#[track_caller]` cannot tail-call one that is",
-                )
-                .emit(),
-        };
+    fn report_track_caller_caller(&mut self, sp: Span) {
+        let err = self
+            .tcx
+            .dcx()
+            .struct_span_err(
+                sp,
+                "a function marked with `#[track_caller]` cannot perform a tail-call",
+            )
+            .emit();
 
         self.found_errors = Err(err);
     }
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index af6f33d9cdd..07bdc59756a 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::codes::*;
 use rustc_errors::{
     Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
@@ -1097,41 +1098,70 @@ pub(crate) enum MiscPatternSuggestion {
 
 #[derive(LintDiagnostic)]
 #[diag(mir_build_rust_2024_incompatible_pat)]
-pub(crate) struct Rust2024IncompatiblePat<'a> {
+pub(crate) struct Rust2024IncompatiblePat {
     #[subdiagnostic]
-    pub(crate) sugg: Rust2024IncompatiblePatSugg<'a>,
+    pub(crate) sugg: Rust2024IncompatiblePatSugg,
+    pub(crate) bad_modifiers: bool,
+    pub(crate) bad_ref_pats: bool,
+    pub(crate) is_hard_error: bool,
 }
 
-pub(crate) struct Rust2024IncompatiblePatSugg<'a> {
+pub(crate) struct Rust2024IncompatiblePatSugg {
+    /// If true, our suggestion is to elide explicit binding modifiers.
+    /// If false, our suggestion is to make the pattern fully explicit.
+    pub(crate) suggest_eliding_modes: bool,
     pub(crate) suggestion: Vec<(Span, String)>,
     pub(crate) ref_pattern_count: usize,
     pub(crate) binding_mode_count: usize,
-    /// Labeled spans for subpatterns invalid in Rust 2024.
-    pub(crate) labels: &'a [(Span, String)],
+    /// Internal state: the ref-mutability of the default binding mode at the subpattern being
+    /// lowered, with the span where it was introduced. `None` for a by-value default mode.
+    pub(crate) default_mode_span: Option<(Span, ty::Mutability)>,
+    /// Labels for where incompatibility-causing by-ref default binding modes were introduced.
+    pub(crate) default_mode_labels: FxIndexMap<Span, ty::Mutability>,
 }
 
-impl<'a> Subdiagnostic for Rust2024IncompatiblePatSugg<'a> {
+impl Subdiagnostic for Rust2024IncompatiblePatSugg {
     fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
         self,
         diag: &mut Diag<'_, G>,
         _f: &F,
     ) {
+        // Format and emit explanatory notes about default binding modes. Reversing the spans' order
+        // means if we have nested spans, the innermost ones will be visited first.
+        for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() {
+            // Don't point to a macro call site.
+            if !span.from_expansion() {
+                let note_msg = "matching on a reference type with a non-reference pattern changes the default binding mode";
+                let label_msg =
+                    format!("this matches on type `{}_`", def_br_mutbl.ref_prefix_str());
+                let mut label = MultiSpan::from(span);
+                label.push_span_label(span, label_msg);
+                diag.span_note(label, note_msg);
+            }
+        }
+
+        // Format and emit the suggestion.
         let applicability =
             if self.suggestion.iter().all(|(span, _)| span.can_be_used_for_suggestions()) {
                 Applicability::MachineApplicable
             } else {
                 Applicability::MaybeIncorrect
             };
-        let plural_derefs = pluralize!(self.ref_pattern_count);
-        let and_modes = if self.binding_mode_count > 0 {
-            format!(" and variable binding mode{}", pluralize!(self.binding_mode_count))
+        let msg = if self.suggest_eliding_modes {
+            let plural_modes = pluralize!(self.binding_mode_count);
+            format!("remove the unnecessary binding modifier{plural_modes}")
         } else {
-            String::new()
+            let plural_derefs = pluralize!(self.ref_pattern_count);
+            let and_modes = if self.binding_mode_count > 0 {
+                format!(" and variable binding mode{}", pluralize!(self.binding_mode_count))
+            } else {
+                String::new()
+            };
+            format!("make the implied reference pattern{plural_derefs}{and_modes} explicit")
         };
-        diag.multipart_suggestion_verbose(
-            format!("make the implied reference pattern{plural_derefs}{and_modes} explicit"),
-            self.suggestion,
-            applicability,
-        );
+        // FIXME(dianne): for peace of mind, don't risk emitting a 0-part suggestion (that panics!)
+        if !self.suggestion.is_empty() {
+            diag.multipart_suggestion_verbose(msg, self.suggestion, applicability);
+        }
     }
 }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index c862d012f4e..83fef7b0de6 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -35,7 +35,7 @@ struct PatCtxt<'a, 'tcx> {
     typeck_results: &'a ty::TypeckResults<'tcx>,
 
     /// Used by the Rust 2024 migration lint.
-    rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg<'a>>,
+    rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg>,
 }
 
 pub(super) fn pat_from_hir<'a, 'tcx>(
@@ -44,25 +44,30 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
     typeck_results: &'a ty::TypeckResults<'tcx>,
     pat: &'tcx hir::Pat<'tcx>,
 ) -> Box<Pat<'tcx>> {
+    let migration_info = typeck_results.rust_2024_migration_desugared_pats().get(pat.hir_id);
     let mut pcx = PatCtxt {
         tcx,
         typing_env,
         typeck_results,
-        rust_2024_migration_suggestion: typeck_results
-            .rust_2024_migration_desugared_pats()
-            .get(pat.hir_id)
-            .map(|labels| Rust2024IncompatiblePatSugg {
+        rust_2024_migration_suggestion: migration_info.and_then(|info| {
+            Some(Rust2024IncompatiblePatSugg {
+                suggest_eliding_modes: info.suggest_eliding_modes,
                 suggestion: Vec::new(),
                 ref_pattern_count: 0,
                 binding_mode_count: 0,
-                labels: labels.as_slice(),
-            }),
+                default_mode_span: None,
+                default_mode_labels: Default::default(),
+            })
+        }),
     };
     let result = pcx.lower_pattern(pat);
     debug!("pat_from_hir({:?}) = {:?}", pat, result);
-    if let Some(sugg) = pcx.rust_2024_migration_suggestion {
-        let mut spans = MultiSpan::from_spans(sugg.labels.iter().map(|(span, _)| *span).collect());
-        for (span, label) in sugg.labels {
+    if let Some(info) = migration_info
+        && let Some(sugg) = pcx.rust_2024_migration_suggestion
+    {
+        let mut spans =
+            MultiSpan::from_spans(info.primary_labels.iter().map(|(span, _)| *span).collect());
+        for (span, label) in &info.primary_labels {
             spans.push_span_label(*span, label.clone());
         }
         // If a relevant span is from at least edition 2024, this is a hard error.
@@ -70,10 +75,13 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
         if is_hard_error {
             let mut err =
                 tcx.dcx().struct_span_err(spans, fluent::mir_build_rust_2024_incompatible_pat);
-            if let Some(info) = lint::builtin::RUST_2024_INCOMPATIBLE_PAT.future_incompatible {
+            if let Some(lint_info) = lint::builtin::RUST_2024_INCOMPATIBLE_PAT.future_incompatible {
                 // provide the same reference link as the lint
-                err.note(format!("for more information, see {}", info.reference));
+                err.note(format!("for more information, see {}", lint_info.reference));
             }
+            err.arg("bad_modifiers", info.bad_modifiers);
+            err.arg("bad_ref_pats", info.bad_ref_pats);
+            err.arg("is_hard_error", true);
             err.subdiagnostic(sugg);
             err.emit();
         } else {
@@ -81,7 +89,12 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
                 lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
                 pat.hir_id,
                 spans,
-                Rust2024IncompatiblePat { sugg },
+                Rust2024IncompatiblePat {
+                    sugg,
+                    bad_modifiers: info.bad_modifiers,
+                    bad_ref_pats: info.bad_ref_pats,
+                    is_hard_error,
+                },
             );
         }
     }
@@ -90,6 +103,35 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
 
 impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
+        let adjustments: &[Ty<'tcx>] =
+            self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
+
+        let mut opt_old_mode_span = None;
+        if let Some(s) = &mut self.rust_2024_migration_suggestion
+            && !adjustments.is_empty()
+        {
+            let implicit_deref_mutbls = adjustments.iter().map(|ref_ty| {
+                let &ty::Ref(_, _, mutbl) = ref_ty.kind() else {
+                    span_bug!(pat.span, "pattern implicitly dereferences a non-ref type");
+                };
+                mutbl
+            });
+
+            if !s.suggest_eliding_modes {
+                let suggestion_str: String =
+                    implicit_deref_mutbls.clone().map(|mutbl| mutbl.ref_prefix_str()).collect();
+                s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str));
+                s.ref_pattern_count += adjustments.len();
+            }
+
+            // Remember if this changed the default binding mode, in case we want to label it.
+            let min_mutbl = implicit_deref_mutbls.min().unwrap();
+            if s.default_mode_span.is_none_or(|(_, old_mutbl)| min_mutbl < old_mutbl) {
+                opt_old_mode_span = Some(s.default_mode_span);
+                s.default_mode_span = Some((pat.span, min_mutbl));
+            }
+        };
+
         // When implicit dereferences have been inserted in this pattern, the unadjusted lowered
         // pattern has the type that results *after* dereferencing. For example, in this code:
         //
@@ -118,8 +160,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             _ => self.lower_pattern_unadjusted(pat),
         };
 
-        let adjustments: &[Ty<'tcx>] =
-            self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
         let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| {
             debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty);
             Box::new(Pat {
@@ -130,24 +170,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         });
 
         if let Some(s) = &mut self.rust_2024_migration_suggestion
-            && !adjustments.is_empty()
+            && let Some(old_mode_span) = opt_old_mode_span
         {
-            let suggestion_str: String = adjustments
-                .iter()
-                .map(|ref_ty| {
-                    let &ty::Ref(_, _, mutbl) = ref_ty.kind() else {
-                        span_bug!(pat.span, "pattern implicitly dereferences a non-ref type");
-                    };
-
-                    match mutbl {
-                        ty::Mutability::Not => "&",
-                        ty::Mutability::Mut => "&mut ",
-                    }
-                })
-                .collect();
-            s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str));
-            s.ref_pattern_count += adjustments.len();
-        };
+            s.default_mode_span = old_mode_span;
+        }
 
         adjusted_pat
     }
@@ -340,7 +366,22 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
                 PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), mutability }
             }
-            hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => {
+            hir::PatKind::Ref(subpattern, _) => {
+                // Track the default binding mode for the Rust 2024 migration suggestion.
+                let old_mode_span = self.rust_2024_migration_suggestion.as_mut().and_then(|s| {
+                    if let Some((default_mode_span, default_ref_mutbl)) = s.default_mode_span {
+                        // If this eats a by-ref default binding mode, label the binding mode.
+                        s.default_mode_labels.insert(default_mode_span, default_ref_mutbl);
+                    }
+                    s.default_mode_span.take()
+                });
+                let subpattern = self.lower_pattern(subpattern);
+                if let Some(s) = &mut self.rust_2024_migration_suggestion {
+                    s.default_mode_span = old_mode_span;
+                }
+                PatKind::Deref { subpattern }
+            }
+            hir::PatKind::Box(subpattern) => {
                 PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
             }
 
@@ -367,19 +408,32 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     .get(pat.hir_id)
                     .expect("missing binding mode");
 
-                if let Some(s) = &mut self.rust_2024_migration_suggestion
-                    && explicit_ba.0 == ByRef::No
-                    && let ByRef::Yes(mutbl) = mode.0
-                {
-                    let sugg_str = match mutbl {
-                        Mutability::Not => "ref ",
-                        Mutability::Mut => "ref mut ",
-                    };
-                    s.suggestion.push((
-                        pat.span.with_lo(ident.span.lo()).shrink_to_lo(),
-                        sugg_str.to_owned(),
-                    ));
-                    s.binding_mode_count += 1;
+                if let Some(s) = &mut self.rust_2024_migration_suggestion {
+                    if explicit_ba != hir::BindingMode::NONE
+                        && let Some((default_mode_span, default_ref_mutbl)) = s.default_mode_span
+                    {
+                        // If this overrides a by-ref default binding mode, label the binding mode.
+                        s.default_mode_labels.insert(default_mode_span, default_ref_mutbl);
+                        // If our suggestion is to elide redundnt modes, this will be one of them.
+                        if s.suggest_eliding_modes {
+                            s.suggestion.push((pat.span.with_hi(ident.span.lo()), String::new()));
+                            s.binding_mode_count += 1;
+                        }
+                    }
+                    if !s.suggest_eliding_modes
+                        && explicit_ba.0 == ByRef::No
+                        && let ByRef::Yes(mutbl) = mode.0
+                    {
+                        let sugg_str = match mutbl {
+                            Mutability::Not => "ref ",
+                            Mutability::Mut => "ref mut ",
+                        };
+                        s.suggestion.push((
+                            pat.span.with_lo(ident.span.lo()).shrink_to_lo(),
+                            sugg_str.to_owned(),
+                        ));
+                        s.binding_mode_count += 1;
+                    }
                 }
 
                 // A ref x pattern is the same node used for x, and as such it has
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index b7a3770fc6b..4ac3a268c9c 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -97,6 +97,12 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
     }
 }
 
+/// This checker covers basic properties of the control-flow graph, (dis)allowed statements and terminators.
+/// Everything checked here must be stable under substitution of generic parameters. In other words,
+/// this is about the *structure* of the MIR, not the *contents*.
+///
+/// Everything that depends on types, or otherwise can be affected by generic parameters,
+/// must be checked in `TypeChecker`.
 struct CfgChecker<'a, 'tcx> {
     when: &'a str,
     body: &'a Body<'tcx>,
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 3ef061195da..e7d7cd25c85 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -1238,9 +1238,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitio
                         Linkage::LinkOnceODR => "OnceODR",
                         Linkage::WeakAny => "WeakAny",
                         Linkage::WeakODR => "WeakODR",
-                        Linkage::Appending => "Appending",
                         Linkage::Internal => "Internal",
-                        Linkage::Private => "Private",
                         Linkage::ExternalWeak => "ExternalWeak",
                         Linkage::Common => "Common",
                     };
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
index a0d41110d96..0bfd72c6848 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
@@ -142,7 +142,7 @@ where
         // Remove any trivial region constraints once we've resolved regions
         external_constraints
             .region_constraints
-            .retain(|outlives| outlives.0.as_region().map_or(true, |re| re != outlives.1));
+            .retain(|outlives| outlives.0.as_region().is_none_or(|re| re != outlives.1));
 
         let canonical = Canonicalizer::canonicalize_response(
             self.delegate,
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index ef8d0f96b61..648a352efd9 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -8,7 +8,7 @@ use crate::errors::TokenSubstitution;
 use crate::token::{self, Delimiter};
 
 #[rustfmt::skip] // for line breaks
-pub(super) const UNICODE_ARRAY: &[(char, &str, &str)] = &[
+pub(super) static UNICODE_ARRAY: &[(char, &str, &str)] = &[
     ('
', "Line Separator", " "),
     ('
', "Paragraph Separator", " "),
     (' ', "Ogham Space mark", " "),
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index f17452b3ba0..0a4ffb15219 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -1,11 +1,11 @@
 use std::fmt;
 use std::str::FromStr;
 
+use rustc_abi::Size;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::Symbol;
 
-use crate::abi::Size;
 use crate::spec::{RelocModel, Target};
 
 pub struct ModifierInfo {
diff --git a/compiler/rustc_target/src/callconv/aarch64.rs b/compiler/rustc_target/src/callconv/aarch64.rs
index 67345f0d47b..d712bec9b78 100644
--- a/compiler/rustc_target/src/callconv/aarch64.rs
+++ b/compiler/rustc_target/src/callconv/aarch64.rs
@@ -1,9 +1,8 @@
 use std::iter;
 
-use rustc_abi::{BackendRepr, Primitive};
+use rustc_abi::{BackendRepr, HasDataLayout, Primitive, TyAbiInterface};
 
 use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
-use crate::abi::{HasDataLayout, TyAbiInterface};
 use crate::spec::{HasTargetSpec, Target};
 
 /// Indicates the variant of the AArch64 ABI we are compiling for.
diff --git a/compiler/rustc_target/src/callconv/amdgpu.rs b/compiler/rustc_target/src/callconv/amdgpu.rs
index 3007a729a8b..91ac00e0250 100644
--- a/compiler/rustc_target/src/callconv/amdgpu.rs
+++ b/compiler/rustc_target/src/callconv/amdgpu.rs
@@ -1,5 +1,6 @@
+use rustc_abi::{HasDataLayout, TyAbiInterface};
+
 use crate::abi::call::{ArgAbi, FnAbi};
-use crate::abi::{HasDataLayout, TyAbiInterface};
 
 fn classify_ret<'a, Ty, C>(_cx: &C, ret: &mut ArgAbi<'a, Ty>)
 where
diff --git a/compiler/rustc_target/src/callconv/arm.rs b/compiler/rustc_target/src/callconv/arm.rs
index bd6f781fb81..75797daba69 100644
--- a/compiler/rustc_target/src/callconv/arm.rs
+++ b/compiler/rustc_target/src/callconv/arm.rs
@@ -1,5 +1,6 @@
+use rustc_abi::{HasDataLayout, TyAbiInterface};
+
 use crate::abi::call::{ArgAbi, Conv, FnAbi, Reg, RegKind, Uniform};
-use crate::abi::{HasDataLayout, TyAbiInterface};
 use crate::spec::HasTargetSpec;
 
 fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs
index 8bf61cb1337..47566bde6b4 100644
--- a/compiler/rustc_target/src/callconv/loongarch.rs
+++ b/compiler/rustc_target/src/callconv/loongarch.rs
@@ -1,9 +1,10 @@
-use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
-use crate::abi::{
-    self, BackendRepr, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout,
+use rustc_abi::{
+    BackendRepr, ExternAbi, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size,
+    TyAbiInterface, TyAndLayout, Variants,
 };
+
+use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform};
 use crate::spec::HasTargetSpec;
-use crate::spec::abi::Abi as SpecAbi;
 
 #[derive(Copy, Clone)]
 enum RegPassKind {
@@ -42,7 +43,7 @@ where
 {
     match arg_layout.backend_repr {
         BackendRepr::Scalar(scalar) => match scalar.primitive() {
-            abi::Int(..) | abi::Pointer(_) => {
+            Primitive::Int(..) | Primitive::Pointer(_) => {
                 if arg_layout.size.bits() > xlen {
                     return Err(CannotUseFpConv);
                 }
@@ -62,7 +63,7 @@ where
                     _ => return Err(CannotUseFpConv),
                 }
             }
-            abi::Float(_) => {
+            Primitive::Float(_) => {
                 if arg_layout.size.bits() > flen {
                     return Err(CannotUseFpConv);
                 }
@@ -115,8 +116,8 @@ where
             }
             FieldsShape::Arbitrary { .. } => {
                 match arg_layout.variants {
-                    abi::Variants::Multiple { .. } => return Err(CannotUseFpConv),
-                    abi::Variants::Single { .. } | abi::Variants::Empty => (),
+                    Variants::Multiple { .. } => return Err(CannotUseFpConv),
+                    Variants::Single { .. } | Variants::Empty => (),
                 }
                 for i in arg_layout.fields.index_by_increasing_offset() {
                     let field = arg_layout.field(cx, i);
@@ -314,7 +315,7 @@ fn classify_arg<'a, Ty, C>(
 
 fn extend_integer_width<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64) {
     if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
-        if let abi::Int(i, _) = scalar.primitive() {
+        if let Primitive::Int(i, _) = scalar.primitive() {
             // 32-bit integers are always sign-extended
             if i.size().bits() == 32 && xlen > 32 {
                 if let PassMode::Direct(ref mut attrs) = arg.mode {
@@ -363,12 +364,12 @@ where
     }
 }
 
-pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi)
+pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: ExternAbi)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout + HasTargetSpec,
 {
-    if abi == SpecAbi::RustIntrinsic {
+    if abi == ExternAbi::RustIntrinsic {
         return;
     }
 
diff --git a/compiler/rustc_target/src/callconv/mips.rs b/compiler/rustc_target/src/callconv/mips.rs
index 37980a91c76..f7d68822155 100644
--- a/compiler/rustc_target/src/callconv/mips.rs
+++ b/compiler/rustc_target/src/callconv/mips.rs
@@ -1,5 +1,6 @@
+use rustc_abi::{HasDataLayout, Size};
+
 use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
-use crate::abi::{HasDataLayout, Size};
 
 fn classify_ret<Ty, C>(cx: &C, ret: &mut ArgAbi<'_, Ty>, offset: &mut Size)
 where
diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs
index 5bdf4c2ad77..89f324bc313 100644
--- a/compiler/rustc_target/src/callconv/mips64.rs
+++ b/compiler/rustc_target/src/callconv/mips64.rs
@@ -1,12 +1,15 @@
-use crate::abi::call::{
-    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode, Reg, Uniform,
+use rustc_abi::{
+    BackendRepr, FieldsShape, Float, HasDataLayout, Primitive, Reg, Size, TyAbiInterface,
+};
+
+use crate::callconv::{
+    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode, Uniform,
 };
-use crate::abi::{self, HasDataLayout, Size, TyAbiInterface};
 
 fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
     // Always sign extend u32 values on 64-bit mips
-    if let abi::BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
-        if let abi::Int(i, signed) = scalar.primitive() {
+    if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
+        if let Primitive::Int(i, signed) = scalar.primitive() {
             if !signed && i.size().bits() == 32 {
                 if let PassMode::Direct(ref mut attrs) = arg.mode {
                     attrs.ext(ArgExtension::Sext);
@@ -25,9 +28,9 @@ where
     C: HasDataLayout,
 {
     match ret.layout.field(cx, i).backend_repr {
-        abi::BackendRepr::Scalar(scalar) => match scalar.primitive() {
-            abi::Float(abi::F32) => Some(Reg::f32()),
-            abi::Float(abi::F64) => Some(Reg::f64()),
+        BackendRepr::Scalar(scalar) => match scalar.primitive() {
+            Primitive::Float(Float::F32) => Some(Reg::f32()),
+            Primitive::Float(Float::F64) => Some(Reg::f64()),
             _ => None,
         },
         _ => None,
@@ -51,7 +54,7 @@ where
         // use of float registers to structures (not unions) containing exactly one or two
         // float fields.
 
-        if let abi::FieldsShape::Arbitrary { .. } = ret.layout.fields {
+        if let FieldsShape::Arbitrary { .. } = ret.layout.fields {
             if ret.layout.fields.count() == 1 {
                 if let Some(reg) = float_reg(cx, ret, 0) {
                     ret.cast_to(reg);
@@ -90,16 +93,16 @@ where
     let mut prefix_index = 0;
 
     match arg.layout.fields {
-        abi::FieldsShape::Primitive => unreachable!(),
-        abi::FieldsShape::Array { .. } => {
+        FieldsShape::Primitive => unreachable!(),
+        FieldsShape::Array { .. } => {
             // Arrays are passed indirectly
             arg.make_indirect();
             return;
         }
-        abi::FieldsShape::Union(_) => {
+        FieldsShape::Union(_) => {
             // Unions and are always treated as a series of 64-bit integer chunks
         }
-        abi::FieldsShape::Arbitrary { .. } => {
+        FieldsShape::Arbitrary { .. } => {
             // Structures are split up into a series of 64-bit integer chunks, but any aligned
             // doubles not part of another aggregate are passed as floats.
             let mut last_offset = Size::ZERO;
@@ -109,8 +112,8 @@ where
                 let offset = arg.layout.fields.offset(i);
 
                 // We only care about aligned doubles
-                if let abi::BackendRepr::Scalar(scalar) = field.backend_repr {
-                    if scalar.primitive() == abi::Float(abi::F64) {
+                if let BackendRepr::Scalar(scalar) = field.backend_repr {
+                    if scalar.primitive() == Primitive::Float(Float::F64) {
                         if offset.is_aligned(dl.f64_align.abi) {
                             // Insert enough integers to cover [last_offset, offset)
                             assert!(last_offset.is_aligned(dl.f64_align.abi));
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index 41b78d9121d..9e651376cd7 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -1,14 +1,14 @@
 use std::str::FromStr;
 use std::{fmt, iter};
 
-pub use rustc_abi::{ExternAbi, Reg, RegKind};
+use rustc_abi::{
+    AddressSpace, Align, BackendRepr, ExternAbi, HasDataLayout, Scalar, Size, TyAbiInterface,
+    TyAndLayout,
+};
+pub use rustc_abi::{Primitive, Reg, RegKind};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 
-use crate::abi::{
-    self, AddressSpace, Align, BackendRepr, HasDataLayout, Pointer, Size, TyAbiInterface,
-    TyAndLayout,
-};
 use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi};
 
 mod aarch64;
@@ -349,7 +349,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
     pub fn new(
         cx: &impl HasDataLayout,
         layout: TyAndLayout<'a, Ty>,
-        scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, abi::Scalar, Size) -> ArgAttributes,
+        scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, Scalar, Size) -> ArgAttributes,
     ) -> Self {
         let mode = match layout.backend_repr {
             BackendRepr::Uninhabited => PassMode::Ignore,
@@ -464,7 +464,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
     pub fn extend_integer_width_to(&mut self, bits: u64) {
         // Only integers have signedness
         if let BackendRepr::Scalar(scalar) = self.layout.backend_repr {
-            if let abi::Int(i, signed) = scalar.primitive() {
+            if let Primitive::Int(i, signed) = scalar.primitive() {
                 if i.size().bits() < bits {
                     if let PassMode::Direct(ref mut attrs) = self.mode {
                         if signed {
@@ -756,7 +756,9 @@ impl<'a, Ty> FnAbi<'a, Ty> {
                 continue;
             }
 
-            if arg_idx.is_none() && arg.layout.size > Pointer(AddressSpace::DATA).size(cx) * 2 {
+            if arg_idx.is_none()
+                && arg.layout.size > Primitive::Pointer(AddressSpace::DATA).size(cx) * 2
+            {
                 // Return values larger than 2 registers using a return area
                 // pointer. LLVM and Cranelift disagree about how to return
                 // values that don't fit in the registers designated for return
@@ -837,7 +839,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             assert!(is_indirect_not_on_stack);
 
             let size = arg.layout.size;
-            if !arg.layout.is_unsized() && size <= Pointer(AddressSpace::DATA).size(cx) {
+            if !arg.layout.is_unsized() && size <= Primitive::Pointer(AddressSpace::DATA).size(cx) {
                 // We want to pass small aggregates as immediates, but using
                 // an LLVM aggregate type for this leads to bad optimizations,
                 // so we pick an appropriately sized integer type instead.
diff --git a/compiler/rustc_target/src/callconv/nvptx64.rs b/compiler/rustc_target/src/callconv/nvptx64.rs
index c64164372a1..c5da1855658 100644
--- a/compiler/rustc_target/src/callconv/nvptx64.rs
+++ b/compiler/rustc_target/src/callconv/nvptx64.rs
@@ -1,6 +1,7 @@
+use rustc_abi::{HasDataLayout, Reg, Size, TyAbiInterface};
+
 use super::{ArgAttribute, ArgAttributes, ArgExtension, CastTarget};
-use crate::abi::call::{ArgAbi, FnAbi, Reg, Size, Uniform};
-use crate::abi::{HasDataLayout, TyAbiInterface};
+use crate::abi::call::{ArgAbi, FnAbi, Uniform};
 
 fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
     if ret.layout.is_aggregate() && ret.layout.is_sized() {
diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs
index 92c1f6e7148..7a66ce8529a 100644
--- a/compiler/rustc_target/src/callconv/powerpc64.rs
+++ b/compiler/rustc_target/src/callconv/powerpc64.rs
@@ -2,8 +2,9 @@
 // Alignment of 128 bit types is not currently handled, this will
 // need to be fixed when PowerPC vector support is added.
 
+use rustc_abi::{Endian, HasDataLayout, TyAbiInterface};
+
 use crate::abi::call::{Align, ArgAbi, FnAbi, Reg, RegKind, Uniform};
-use crate::abi::{Endian, HasDataLayout, TyAbiInterface};
 use crate::spec::HasTargetSpec;
 
 #[derive(Debug, Clone, Copy, PartialEq)]
diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs
index 4d858392c97..24531b0ef63 100644
--- a/compiler/rustc_target/src/callconv/riscv.rs
+++ b/compiler/rustc_target/src/callconv/riscv.rs
@@ -4,12 +4,13 @@
 // Reference: Clang RISC-V ELF psABI lowering code
 // https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773
 
-use rustc_abi::{BackendRepr, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
+use rustc_abi::{
+    BackendRepr, ExternAbi, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size,
+    TyAbiInterface, TyAndLayout, Variants,
+};
 
-use crate::abi;
-use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
+use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform};
 use crate::spec::HasTargetSpec;
-use crate::spec::abi::Abi as SpecAbi;
 
 #[derive(Copy, Clone)]
 enum RegPassKind {
@@ -48,7 +49,7 @@ where
 {
     match arg_layout.backend_repr {
         BackendRepr::Scalar(scalar) => match scalar.primitive() {
-            abi::Int(..) | abi::Pointer(_) => {
+            Primitive::Int(..) | Primitive::Pointer(_) => {
                 if arg_layout.size.bits() > xlen {
                     return Err(CannotUseFpConv);
                 }
@@ -68,7 +69,7 @@ where
                     _ => return Err(CannotUseFpConv),
                 }
             }
-            abi::Float(_) => {
+            Primitive::Float(_) => {
                 if arg_layout.size.bits() > flen {
                     return Err(CannotUseFpConv);
                 }
@@ -121,8 +122,8 @@ where
             }
             FieldsShape::Arbitrary { .. } => {
                 match arg_layout.variants {
-                    abi::Variants::Multiple { .. } => return Err(CannotUseFpConv),
-                    abi::Variants::Single { .. } | abi::Variants::Empty => (),
+                    Variants::Multiple { .. } => return Err(CannotUseFpConv),
+                    Variants::Single { .. } | Variants::Empty => (),
                 }
                 for i in arg_layout.fields.index_by_increasing_offset() {
                     let field = arg_layout.field(cx, i);
@@ -320,7 +321,7 @@ fn classify_arg<'a, Ty, C>(
 
 fn extend_integer_width<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64) {
     if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
-        if let abi::Int(i, _) = scalar.primitive() {
+        if let Primitive::Int(i, _) = scalar.primitive() {
             // 32-bit integers are always sign-extended
             if i.size().bits() == 32 && xlen > 32 {
                 if let PassMode::Direct(ref mut attrs) = arg.mode {
@@ -369,12 +370,12 @@ where
     }
 }
 
-pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi)
+pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: ExternAbi)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout + HasTargetSpec,
 {
-    if abi == SpecAbi::RustIntrinsic {
+    if abi == ExternAbi::RustIntrinsic {
         return;
     }
 
diff --git a/compiler/rustc_target/src/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs
index a73c1a0f46c..edf57098d6d 100644
--- a/compiler/rustc_target/src/callconv/s390x.rs
+++ b/compiler/rustc_target/src/callconv/s390x.rs
@@ -1,8 +1,9 @@
 // Reference: ELF Application Binary Interface s390x Supplement
 // https://github.com/IBM/s390x-abi
 
+use rustc_abi::{BackendRepr, HasDataLayout, TyAbiInterface};
+
 use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind};
-use crate::abi::{BackendRepr, HasDataLayout, TyAbiInterface};
 use crate::spec::HasTargetSpec;
 
 fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
diff --git a/compiler/rustc_target/src/callconv/sparc.rs b/compiler/rustc_target/src/callconv/sparc.rs
index 37980a91c76..f7d68822155 100644
--- a/compiler/rustc_target/src/callconv/sparc.rs
+++ b/compiler/rustc_target/src/callconv/sparc.rs
@@ -1,5 +1,6 @@
+use rustc_abi::{HasDataLayout, Size};
+
 use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
-use crate::abi::{HasDataLayout, Size};
 
 fn classify_ret<Ty, C>(cx: &C, ret: &mut ArgAbi<'_, Ty>, offset: &mut Size)
 where
diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs
index 313d8730399..392fb5156fc 100644
--- a/compiler/rustc_target/src/callconv/sparc64.rs
+++ b/compiler/rustc_target/src/callconv/sparc64.rs
@@ -1,9 +1,13 @@
 // FIXME: This needs an audit for correctness and completeness.
 
+use rustc_abi::{
+    BackendRepr, FieldsShape, Float, HasDataLayout, Primitive, Reg, Scalar, Size, TyAbiInterface,
+    TyAndLayout,
+};
+
 use crate::abi::call::{
-    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, Reg, Uniform,
+    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, Uniform,
 };
-use crate::abi::{self, HasDataLayout, Scalar, Size, TyAbiInterface, TyAndLayout};
 use crate::spec::HasTargetSpec;
 
 #[derive(Clone, Debug)]
@@ -21,7 +25,7 @@ where
 {
     let dl = cx.data_layout();
 
-    if !matches!(scalar.primitive(), abi::Float(abi::F32 | abi::F64)) {
+    if !matches!(scalar.primitive(), Primitive::Float(Float::F32 | Float::F64)) {
         return data;
     }
 
@@ -57,7 +61,7 @@ where
         return data;
     }
 
-    if scalar.primitive() == abi::Float(abi::F32) {
+    if scalar.primitive() == Primitive::Float(Float::F32) {
         data.arg_attribute = ArgAttribute::InReg;
         data.prefix[data.prefix_index] = Some(Reg::f32());
         data.last_offset = offset + Reg::f32().size;
@@ -81,14 +85,16 @@ where
 {
     data = arg_scalar(cx, scalar1, offset, data);
     match (scalar1.primitive(), scalar2.primitive()) {
-        (abi::Float(abi::F32), _) => offset += Reg::f32().size,
-        (_, abi::Float(abi::F64)) => offset += Reg::f64().size,
-        (abi::Int(i, _signed), _) => offset += i.size(),
-        (abi::Pointer(_), _) => offset += Reg::i64().size,
+        (Primitive::Float(Float::F32), _) => offset += Reg::f32().size,
+        (_, Primitive::Float(Float::F64)) => offset += Reg::f64().size,
+        (Primitive::Int(i, _signed), _) => offset += i.size(),
+        (Primitive::Pointer(_), _) => offset += Reg::i64().size,
         _ => {}
     }
 
-    if (offset.bytes() % 4) != 0 && matches!(scalar2.primitive(), abi::Float(abi::F32 | abi::F64)) {
+    if (offset.bytes() % 4) != 0
+        && matches!(scalar2.primitive(), Primitive::Float(Float::F32 | Float::F64))
+    {
         offset += Size::from_bytes(4 - (offset.bytes() % 4));
     }
     data = arg_scalar(cx, scalar2, offset, data);
@@ -105,15 +111,15 @@ where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout,
 {
-    if let abi::FieldsShape::Union(_) = layout.fields {
+    if let FieldsShape::Union(_) = layout.fields {
         return data;
     }
 
     match layout.backend_repr {
-        abi::BackendRepr::Scalar(scalar) => {
+        BackendRepr::Scalar(scalar) => {
             data = arg_scalar(cx, &scalar, offset, data);
         }
-        abi::BackendRepr::Memory { .. } => {
+        BackendRepr::Memory { .. } => {
             for i in 0..layout.fields.count() {
                 if offset < layout.fields.offset(i) {
                     offset = layout.fields.offset(i);
@@ -122,7 +128,7 @@ where
             }
         }
         _ => {
-            if let abi::BackendRepr::ScalarPair(scalar1, scalar2) = &layout.backend_repr {
+            if let BackendRepr::ScalarPair(scalar1, scalar2) = &layout.backend_repr {
                 data = arg_scalar_pair(cx, scalar1, scalar2, offset, data);
             }
         }
@@ -148,16 +154,16 @@ where
     }
 
     match arg.layout.fields {
-        abi::FieldsShape::Primitive => unreachable!(),
-        abi::FieldsShape::Array { .. } => {
+        FieldsShape::Primitive => unreachable!(),
+        FieldsShape::Array { .. } => {
             // Arrays are passed indirectly
             arg.make_indirect();
             return;
         }
-        abi::FieldsShape::Union(_) => {
+        FieldsShape::Union(_) => {
             // Unions and are always treated as a series of 64-bit integer chunks
         }
-        abi::FieldsShape::Arbitrary { .. } => {
+        FieldsShape::Arbitrary { .. } => {
             // Structures with floating point numbers need special care.
 
             let mut data = parse_structure(
diff --git a/compiler/rustc_target/src/callconv/wasm.rs b/compiler/rustc_target/src/callconv/wasm.rs
index d01b59cbb03..56cd7a3f93d 100644
--- a/compiler/rustc_target/src/callconv/wasm.rs
+++ b/compiler/rustc_target/src/callconv/wasm.rs
@@ -1,7 +1,6 @@
-use rustc_abi::{BackendRepr, Float, Integer, Primitive};
+use rustc_abi::{BackendRepr, Float, HasDataLayout, Integer, Primitive, TyAbiInterface};
 
 use crate::abi::call::{ArgAbi, FnAbi};
-use crate::abi::{HasDataLayout, TyAbiInterface};
 
 fn unwrap_trivial_aggregate<'a, Ty, C>(cx: &C, val: &mut ArgAbi<'a, Ty>) -> bool
 where
diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs
index cd8465c09ca..7c88d9b55cf 100644
--- a/compiler/rustc_target/src/callconv/x86.rs
+++ b/compiler/rustc_target/src/callconv/x86.rs
@@ -1,9 +1,10 @@
-use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind};
-use crate::abi::{
-    AddressSpace, Align, BackendRepr, Float, HasDataLayout, Pointer, TyAbiInterface, TyAndLayout,
+use rustc_abi::{
+    AddressSpace, Align, BackendRepr, ExternAbi, HasDataLayout, Primitive, Reg, RegKind,
+    TyAbiInterface, TyAndLayout,
 };
+
+use crate::abi::call::{ArgAttribute, FnAbi, PassMode};
 use crate::spec::HasTargetSpec;
-use crate::spec::abi::Abi as SpecAbi;
 
 #[derive(PartialEq)]
 pub(crate) enum Flavor {
@@ -214,7 +215,7 @@ pub(crate) fn fill_inregs<'a, Ty, C>(
     }
 }
 
-pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi)
+pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: ExternAbi)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout + HasTargetSpec,
@@ -223,18 +224,19 @@ where
     // registers will quiet signalling NaNs. Also avoid using SSE registers since they
     // are not always available (depending on target features).
     if !fn_abi.ret.is_ignore()
-        // Intrinsics themselves are not actual "real" functions, so theres no need to change their ABIs.
-        && abi != SpecAbi::RustIntrinsic
+        // Intrinsics themselves are not "real" functions, so theres no need to change their ABIs.
+        && abi != ExternAbi::RustIntrinsic
     {
         let has_float = match fn_abi.ret.layout.backend_repr {
-            BackendRepr::Scalar(s) => matches!(s.primitive(), Float(_)),
+            BackendRepr::Scalar(s) => matches!(s.primitive(), Primitive::Float(_)),
             BackendRepr::ScalarPair(s1, s2) => {
-                matches!(s1.primitive(), Float(_)) || matches!(s2.primitive(), Float(_))
+                matches!(s1.primitive(), Primitive::Float(_))
+                    || matches!(s2.primitive(), Primitive::Float(_))
             }
             _ => false, // anyway not passed via registers on x86
         };
         if has_float {
-            if fn_abi.ret.layout.size <= Pointer(AddressSpace::DATA).size(cx) {
+            if fn_abi.ret.layout.size <= Primitive::Pointer(AddressSpace::DATA).size(cx) {
                 // Same size or smaller than pointer, return in a register.
                 fn_abi.ret.cast_to(Reg { kind: RegKind::Integer, size: fn_abi.ret.layout.size });
             } else {
diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs
index 37aecf323a1..6e9b4690a2c 100644
--- a/compiler/rustc_target/src/callconv/x86_64.rs
+++ b/compiler/rustc_target/src/callconv/x86_64.rs
@@ -1,10 +1,12 @@
 // The classification code for the x86_64 ABI is taken from the clay language
 // https://github.com/jckarter/clay/blob/db0bd2702ab0b6e48965cd85f8859bbd5f60e48e/compiler/externals.cpp
 
-use rustc_abi::{BackendRepr, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
+use rustc_abi::{
+    BackendRepr, HasDataLayout, Primitive, Reg, RegKind, Size, TyAbiInterface, TyAndLayout,
+    Variants,
+};
 
-use crate::abi;
-use crate::abi::call::{ArgAbi, CastTarget, FnAbi, Reg, RegKind};
+use crate::abi::call::{ArgAbi, CastTarget, FnAbi};
 
 /// Classification of "eightbyte" components.
 // N.B., the order of the variants is from general to specific,
@@ -52,8 +54,8 @@ where
             BackendRepr::Uninhabited => return Ok(()),
 
             BackendRepr::Scalar(scalar) => match scalar.primitive() {
-                abi::Int(..) | abi::Pointer(_) => Class::Int,
-                abi::Float(_) => Class::Sse,
+                Primitive::Int(..) | Primitive::Pointer(_) => Class::Int,
+                Primitive::Float(_) => Class::Sse,
             },
 
             BackendRepr::Vector { .. } => Class::Sse,
@@ -65,8 +67,8 @@ where
                 }
 
                 match &layout.variants {
-                    abi::Variants::Single { .. } | abi::Variants::Empty => {}
-                    abi::Variants::Multiple { variants, .. } => {
+                    Variants::Single { .. } | Variants::Empty => {}
+                    Variants::Multiple { variants, .. } => {
                         // Treat enum variants like union members.
                         for variant_idx in variants.indices() {
                             classify(cx, layout.for_variant(cx, variant_idx), cls, off)?;
diff --git a/compiler/rustc_target/src/callconv/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs
index 9d313d16500..2542713bc11 100644
--- a/compiler/rustc_target/src/callconv/xtensa.rs
+++ b/compiler/rustc_target/src/callconv/xtensa.rs
@@ -5,8 +5,9 @@
 //! Section 8.1.4 & 8.1.5 of the Xtensa ISA reference manual, as well as snippets from
 //! Section 2.3 from the Xtensa programmers guide.
 
+use rustc_abi::{BackendRepr, HasDataLayout, Size, TyAbiInterface};
+
 use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
-use crate::abi::{BackendRepr, HasDataLayout, Size, TyAbiInterface};
 use crate::spec::HasTargetSpec;
 
 const NUM_ARG_GPRS: u64 = 6;
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index 50679ab8cc8..11fc09d26e4 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -31,10 +31,7 @@ pub mod target_features;
 mod tests;
 
 pub mod abi {
-    pub(crate) use Float::*;
-    pub(crate) use Primitive::*;
-    // Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
-    pub use rustc_abi::{Float, *};
+    pub use rustc_abi::*;
 
     pub use crate::callconv as call;
 }
diff --git a/compiler/rustc_target/src/spec/base/aix.rs b/compiler/rustc_target/src/spec/base/aix.rs
index fe37d313294..a92d104f910 100644
--- a/compiler/rustc_target/src/spec/base/aix.rs
+++ b/compiler/rustc_target/src/spec/base/aix.rs
@@ -1,4 +1,5 @@
-use crate::abi::Endian;
+use rustc_abi::Endian;
+
 use crate::spec::{Cc, CodeModel, LinkOutputKind, LinkerFlavor, TargetOptions, crt_objects, cvs};
 
 pub(crate) fn opts() -> TargetOptions {
diff --git a/compiler/rustc_target/src/spec/base/bpf.rs b/compiler/rustc_target/src/spec/base/bpf.rs
index 17d5e75ef6d..7c0e2e165b6 100644
--- a/compiler/rustc_target/src/spec/base/bpf.rs
+++ b/compiler/rustc_target/src/spec/base/bpf.rs
@@ -1,4 +1,5 @@
-use crate::abi::Endian;
+use rustc_abi::Endian;
+
 use crate::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, TargetOptions};
 
 pub(crate) fn opts(endian: Endian) -> TargetOptions {
diff --git a/compiler/rustc_target/src/spec/base/xtensa.rs b/compiler/rustc_target/src/spec/base/xtensa.rs
index 280dd16e264..47a532dfdd4 100644
--- a/compiler/rustc_target/src/spec/base/xtensa.rs
+++ b/compiler/rustc_target/src/spec/base/xtensa.rs
@@ -1,4 +1,5 @@
-use crate::abi::Endian;
+use rustc_abi::Endian;
+
 use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, TargetOptions};
 
 pub(crate) fn opts() -> TargetOptions {
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 72600225e7a..e95c4dbd2cf 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -42,6 +42,7 @@ use std::path::{Path, PathBuf};
 use std::str::FromStr;
 use std::{fmt, io};
 
+use rustc_abi::{Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_fs_util::try_canonicalize;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
@@ -51,9 +52,7 @@ use serde_json::Value;
 use tracing::debug;
 
 use crate::abi::call::Conv;
-use crate::abi::{Endian, Integer, Size, TargetDataLayout, TargetDataLayoutErrors};
 use crate::json::{Json, ToJson};
-use crate::spec::abi::Abi;
 use crate::spec::crt_objects::CrtObjects;
 
 pub mod crt_objects;
@@ -1651,7 +1650,7 @@ macro_rules! supported_targets {
         }
 
         /// List of supported targets
-        pub const TARGETS: &[&str] = &[$($tuple),+];
+        pub static TARGETS: &[&str] = &[$($tuple),+];
 
         fn load_builtin(target: &str) -> Option<Target> {
             let t = match target {
@@ -2845,44 +2844,40 @@ impl DerefMut for Target {
 
 impl Target {
     /// Given a function ABI, turn it into the correct ABI for this target.
-    pub fn adjust_abi(&self, abi: Abi, c_variadic: bool) -> Abi {
+    pub fn adjust_abi(&self, abi: ExternAbi, c_variadic: bool) -> ExternAbi {
+        use ExternAbi::*;
         match abi {
             // On Windows, `extern "system"` behaves like msvc's `__stdcall`.
             // `__stdcall` only applies on x86 and on non-variadic functions:
             // https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170
-            Abi::System { unwind } if self.is_like_windows && self.arch == "x86" && !c_variadic => {
-                Abi::Stdcall { unwind }
+            System { unwind } if self.is_like_windows && self.arch == "x86" && !c_variadic => {
+                Stdcall { unwind }
             }
-            Abi::System { unwind } => Abi::C { unwind },
-            Abi::EfiApi if self.arch == "arm" => Abi::Aapcs { unwind: false },
-            Abi::EfiApi if self.arch == "x86_64" => Abi::Win64 { unwind: false },
-            Abi::EfiApi => Abi::C { unwind: false },
-
-            // See commentary in `is_abi_supported`: we map these ABIs to "C" when they do not make sense.
-            Abi::Stdcall { .. } | Abi::Thiscall { .. } | Abi::Fastcall { .. }
-                if self.arch == "x86" =>
-            {
-                abi
-            }
-            Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
-            Abi::Stdcall { unwind }
-            | Abi::Thiscall { unwind }
-            | Abi::Fastcall { unwind }
-            | Abi::Vectorcall { unwind } => Abi::C { unwind },
+            System { unwind } => C { unwind },
+            EfiApi if self.arch == "arm" => Aapcs { unwind: false },
+            EfiApi if self.arch == "x86_64" => Win64 { unwind: false },
+            EfiApi => C { unwind: false },
+
+            // See commentary in `is_abi_supported`.
+            Stdcall { .. } | Thiscall { .. } if self.arch == "x86" => abi,
+            Stdcall { unwind } | Thiscall { unwind } => C { unwind },
+            Fastcall { .. } if self.arch == "x86" => abi,
+            Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
+            Fastcall { unwind } | Vectorcall { unwind } => C { unwind },
 
             // The Windows x64 calling convention we use for `extern "Rust"`
             // <https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions#register-volatility-and-preservation>
             // expects the callee to save `xmm6` through `xmm15`, but `PreserveMost`
             // (that we use by default for `extern "rust-cold"`) doesn't save any of those.
             // So to avoid bloating callers, just use the Rust convention here.
-            Abi::RustCold if self.is_like_windows && self.arch == "x86_64" => Abi::Rust,
+            RustCold if self.is_like_windows && self.arch == "x86_64" => Rust,
 
             abi => abi,
         }
     }
 
-    pub fn is_abi_supported(&self, abi: Abi) -> bool {
-        use Abi::*;
+    pub fn is_abi_supported(&self, abi: ExternAbi) -> bool {
+        use ExternAbi::*;
         match abi {
             Rust
             | C { .. }
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs
index 3961656d1b6..2f93e97d9fc 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs
@@ -2,7 +2,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::hurd_gnu::opts();
-    base.cpu = "pentiumpro".into();
+    base.cpu = "pentium4".into();
     base.max_atomic_width = Some(64);
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]);
     base.stack_probes = StackProbeType::Inline;
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index eb2417e0a20..e423ca71dfc 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -131,7 +131,7 @@ impl Stability {
 // Both of these are also applied transitively.
 type ImpliedFeatures = &'static [&'static str];
 
-const ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
+static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     ("aclass", Unstable(sym::arm_target_feature), &[]),
     ("aes", Unstable(sym::arm_target_feature), &["neon"]),
@@ -175,7 +175,7 @@ const ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-end
 ];
 
-const AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
+static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     // FEAT_AES & FEAT_PMULL
     ("aes", Stable, &["neon"]),
@@ -371,7 +371,7 @@ const AARCH64_TIED_FEATURES: &[&[&str]] = &[
     &["paca", "pacg"], // Together these represent `pauth` in LLVM
 ];
 
-const X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
+static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     ("adx", Stable, &[]),
     ("aes", Stable, &["sse2"]),
@@ -453,7 +453,7 @@ const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-end
 ];
 
-const POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
+static POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     ("altivec", Unstable(sym::powerpc_target_feature), &[]),
     ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]),
@@ -476,7 +476,7 @@ const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-end
 ];
 
-const RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
+static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     ("a", Stable, &["zaamo", "zalrsc"]),
     ("c", Stable, &[]),
@@ -521,7 +521,7 @@ const RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-end
 ];
 
-const WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
+static WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     ("atomics", Unstable(sym::wasm_target_feature), &[]),
     ("bulk-memory", Stable, &[]),
@@ -542,7 +542,7 @@ const WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
 const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] =
     &[("alu32", Unstable(sym::bpf_target_feature), &[])];
 
-const CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
+static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     ("10e60", Unstable(sym::csky_target_feature), &["7e10"]),
     ("2e3", Unstable(sym::csky_target_feature), &["e2"]),
@@ -589,7 +589,7 @@ const CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-end
 ];
 
-const LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
+static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     ("d", Unstable(sym::loongarch_target_feature), &["f"]),
     ("f", Unstable(sym::loongarch_target_feature), &[]),
@@ -618,7 +618,7 @@ const SPARC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-end
 ];
 
-const M68K_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
+static M68K_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     ("isa-68000", Unstable(sym::m68k_target_feature), &[]),
     ("isa-68010", Unstable(sym::m68k_target_feature), &["isa-68000"]),
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 13a6744c2e9..e495bdbf782 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -12,9 +12,7 @@ use hir::LangItem;
 use hir::def_id::DefId;
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_hir as hir;
-use rustc_infer::traits::{
-    Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError,
-};
+use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode};
 use rustc_middle::{bug, span_bug};
@@ -23,8 +21,6 @@ use tracing::{debug, instrument, trace};
 
 use super::SelectionCandidate::*;
 use super::{BuiltinImplConditions, SelectionCandidateSet, SelectionContext, TraitObligationStack};
-use crate::traits;
-use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::util;
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
@@ -904,54 +900,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         })
     }
 
-    /// Temporary migration for #89190
-    fn need_migrate_deref_output_trait_object(
-        &mut self,
-        ty: Ty<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        cause: &ObligationCause<'tcx>,
-    ) -> Option<ty::PolyExistentialTraitRef<'tcx>> {
-        // Don't drop any candidates in intercrate mode, as it's incomplete.
-        // (Not that it matters, since `Unsize` is not a stable trait.)
-        //
-        // FIXME(@lcnr): This should probably only trigger during analysis,
-        // disabling candidates during codegen is also questionable.
-        if let TypingMode::Coherence = self.infcx.typing_mode() {
-            return None;
-        }
-
-        let tcx = self.tcx();
-        if tcx.features().trait_upcasting() {
-            return None;
-        }
-
-        // <ty as Deref>
-        let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
-
-        let obligation =
-            traits::Obligation::new(tcx, cause.clone(), param_env, ty::Binder::dummy(trait_ref));
-        if !self.infcx.predicate_may_hold(&obligation) {
-            return None;
-        }
-
-        self.infcx.probe(|_| {
-            let ty = traits::normalize_projection_ty(
-                self,
-                param_env,
-                ty::AliasTy::new_from_args(tcx, tcx.lang_items().deref_target()?, trait_ref.args),
-                cause.clone(),
-                0,
-                // We're *intentionally* throwing these away,
-                // since we don't actually use them.
-                &mut PredicateObligations::new(),
-            )
-            .as_type()
-            .unwrap();
-
-            if let ty::Dynamic(data, ..) = ty.kind() { data.principal() } else { None }
-        })
-    }
-
     /// Searches for unsizing that might apply to `obligation`.
     fn assemble_candidates_for_unsizing(
         &mut self,
@@ -1019,15 +967,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     let principal_a = a_data.principal().unwrap();
                     let target_trait_did = principal_def_id_b.unwrap();
                     let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
-                    if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object(
-                        source,
-                        obligation.param_env,
-                        &obligation.cause,
-                    ) {
-                        if deref_trait_ref.def_id() == target_trait_did {
-                            return;
-                        }
-                    }
 
                     for (idx, upcast_trait_ref) in
                         util::supertraits(self.tcx(), source_trait_ref).enumerate()
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index a6c72da0c56..aae2d2e96b9 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -141,6 +141,12 @@ pub trait Interner:
     type VariancesOf: Copy + Debug + SliceLike<Item = ty::Variance>;
     fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf;
 
+    fn opt_alias_variances(
+        self,
+        kind: impl Into<ty::AliasTermKind>,
+        def_id: Self::DefId,
+    ) -> Option<Self::VariancesOf>;
+
     fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>;
 
     type AdtDef: AdtDef<Self>;
diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs
index c26e211a794..b09a378d341 100644
--- a/compiler/rustc_type_ir/src/outlives.rs
+++ b/compiler/rustc_type_ir/src/outlives.rs
@@ -148,7 +148,7 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
             // trait-ref. Therefore, if we see any higher-ranked regions,
             // we simply fallback to the most restrictive rule, which
             // requires that `Pi: 'a` for all `i`.
-            ty::Alias(_, alias_ty) => {
+            ty::Alias(kind, alias_ty) => {
                 if !alias_ty.has_escaping_bound_vars() {
                     // best case: no escaping regions, so push the
                     // projection and skip the subtree (thus generating no
@@ -162,7 +162,7 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
                     // OutlivesProjectionComponents. Continue walking
                     // through and constrain Pi.
                     let mut subcomponents = smallvec![];
-                    compute_alias_components_recursive(self.cx, ty, &mut subcomponents);
+                    compute_alias_components_recursive(self.cx, kind, alias_ty, &mut subcomponents);
                     self.out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
                 }
             }
@@ -217,21 +217,17 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
     }
 }
 
-/// Collect [Component]s for *all* the args of `parent`.
+/// Collect [Component]s for *all* the args of `alias_ty`.
 ///
-/// This should not be used to get the components of `parent` itself.
+/// This should not be used to get the components of `alias_ty` itself.
 /// Use [push_outlives_components] instead.
 pub fn compute_alias_components_recursive<I: Interner>(
     cx: I,
-    alias_ty: I::Ty,
+    kind: ty::AliasTyKind,
+    alias_ty: ty::AliasTy<I>,
     out: &mut SmallVec<[Component<I>; 4]>,
 ) {
-    let ty::Alias(kind, alias_ty) = alias_ty.kind() else {
-        unreachable!("can only call `compute_alias_components_recursive` on an alias type")
-    };
-
-    let opt_variances =
-        if kind == ty::Opaque { Some(cx.variances_of(alias_ty.def_id)) } else { None };
+    let opt_variances = cx.opt_alias_variances(kind, alias_ty.def_id);
 
     let mut visitor = OutlivesCollector { cx, out, visited: Default::default() };
 
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index 9a80f97e274..f75b2927600 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -469,6 +469,17 @@ impl AliasTermKind {
     }
 }
 
+impl From<ty::AliasTyKind> for AliasTermKind {
+    fn from(value: ty::AliasTyKind) -> Self {
+        match value {
+            ty::Projection => AliasTermKind::ProjectionTy,
+            ty::Opaque => AliasTermKind::OpaqueTy,
+            ty::Weak => AliasTermKind::WeakTy,
+            ty::Inherent => AliasTermKind::InherentTy,
+        }
+    }
+}
+
 /// Represents the unprojected term of a projection goal.
 ///
 /// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs
index 5b696ee5ed4..d065384b58e 100644
--- a/compiler/rustc_type_ir/src/relate.rs
+++ b/compiler/rustc_type_ir/src/relate.rs
@@ -236,28 +236,14 @@ impl<I: Interner> Relate<I> for ty::AliasTy<I> {
                 ExpectedFound::new(a, b)
             }))
         } else {
-            let args = match a.kind(relation.cx()) {
-                ty::Opaque => relate_args_with_variances(
-                    relation,
-                    a.def_id,
-                    relation.cx().variances_of(a.def_id),
-                    a.args,
-                    b.args,
+            let cx = relation.cx();
+            let args = if let Some(variances) = cx.opt_alias_variances(a.kind(cx), a.def_id) {
+                relate_args_with_variances(
+                    relation, a.def_id, variances, a.args, b.args,
                     false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
-                )?,
-                ty::Projection if relation.cx().is_impl_trait_in_trait(a.def_id) => {
-                    relate_args_with_variances(
-                        relation,
-                        a.def_id,
-                        relation.cx().variances_of(a.def_id),
-                        a.args,
-                        b.args,
-                        false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
-                    )?
-                }
-                ty::Projection | ty::Weak | ty::Inherent => {
-                    relate_args_invariantly(relation, a.args, b.args)?
-                }
+                )?
+            } else {
+                relate_args_invariantly(relation, a.args, b.args)?
             };
             Ok(ty::AliasTy::new_from_args(relation.cx(), a.def_id, args))
         }
diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs
index c06004d4d0f..a562b751d8a 100644
--- a/compiler/rustc_type_ir/src/solve/mod.rs
+++ b/compiler/rustc_type_ir/src/solve/mod.rs
@@ -179,9 +179,7 @@ pub enum BuiltinImplSource {
     Object(usize),
     /// A built-in implementation of `Upcast` for trait objects to other trait objects.
     ///
-    /// This can be removed when `feature(dyn_upcasting)` is stabilized, since we only
-    /// use it to detect when upcasting traits in hir typeck. The index is only used
-    /// for winnowing.
+    /// The index is only used for winnowing.
     TraitUpcasting(usize),
     /// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`.
     ///
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index c7d6d8a55c2..07c75677d05 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -965,8 +965,9 @@ impl Default for Rc<CStr> {
     /// This may or may not share an allocation with other Rcs on the same thread.
     #[inline]
     fn default() -> Self {
-        let c_str: &CStr = Default::default();
-        Rc::from(c_str)
+        let rc = Rc::<[u8]>::from(*b"\0");
+        // `[u8]` has the same layout as `CStr`, and it is `NUL` terminated.
+        unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) }
     }
 }
 
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index ae3318b839d..05e76ccf685 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -2369,7 +2369,9 @@ impl Default for Rc<str> {
     /// This may or may not share an allocation with other Rcs on the same thread.
     #[inline]
     fn default() -> Self {
-        Rc::from("")
+        let rc = Rc::<[u8]>::default();
+        // `[u8]` has the same layout as `str`.
+        unsafe { Rc::from_raw(Rc::into_raw(rc) as *const str) }
     }
 }
 
diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs
index 6f930ab0853..5720d3ffd97 100644
--- a/library/alloc/tests/str.rs
+++ b/library/alloc/tests/str.rs
@@ -2297,21 +2297,21 @@ fn utf8_chars() {
     assert_eq!(schs.len(), 4);
     assert_eq!(schs.iter().cloned().collect::<String>(), s);
 
-    assert!((from_utf8(s.as_bytes()).is_ok()));
+    assert!(from_utf8(s.as_bytes()).is_ok());
     // invalid prefix
-    assert!((!from_utf8(&[0x80]).is_ok()));
+    assert!(!from_utf8(&[0x80]).is_ok());
     // invalid 2 byte prefix
-    assert!((!from_utf8(&[0xc0]).is_ok()));
-    assert!((!from_utf8(&[0xc0, 0x10]).is_ok()));
+    assert!(!from_utf8(&[0xc0]).is_ok());
+    assert!(!from_utf8(&[0xc0, 0x10]).is_ok());
     // invalid 3 byte prefix
-    assert!((!from_utf8(&[0xe0]).is_ok()));
-    assert!((!from_utf8(&[0xe0, 0x10]).is_ok()));
-    assert!((!from_utf8(&[0xe0, 0xff, 0x10]).is_ok()));
+    assert!(!from_utf8(&[0xe0]).is_ok());
+    assert!(!from_utf8(&[0xe0, 0x10]).is_ok());
+    assert!(!from_utf8(&[0xe0, 0xff, 0x10]).is_ok());
     // invalid 4 byte prefix
-    assert!((!from_utf8(&[0xf0]).is_ok()));
-    assert!((!from_utf8(&[0xf0, 0x10]).is_ok()));
-    assert!((!from_utf8(&[0xf0, 0xff, 0x10]).is_ok()));
-    assert!((!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok()));
+    assert!(!from_utf8(&[0xf0]).is_ok());
+    assert!(!from_utf8(&[0xf0, 0x10]).is_ok());
+    assert!(!from_utf8(&[0xf0, 0xff, 0x10]).is_ok());
+    assert!(!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok());
 }
 
 #[test]
diff --git a/library/coretests/tests/bool.rs b/library/coretests/tests/bool.rs
index 47f6459915b..bcd6dc2abac 100644
--- a/library/coretests/tests/bool.rs
+++ b/library/coretests/tests/bool.rs
@@ -71,14 +71,14 @@ fn test_bool() {
 #[test]
 pub fn test_bool_not() {
     if !false {
-        assert!((true));
+        assert!(true);
     } else {
-        assert!((false));
+        assert!(false);
     }
     if !true {
-        assert!((false));
+        assert!(false);
     } else {
-        assert!((true));
+        assert!(true);
     }
 }
 
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index 7fe72862608..f1bbed3de30 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -81,7 +81,6 @@
 #![feature(strict_provenance_atomic_ptr)]
 #![feature(strict_provenance_lints)]
 #![feature(test)]
-#![feature(trait_upcasting)]
 #![feature(trusted_len)]
 #![feature(trusted_random_access)]
 #![feature(try_blocks)]
diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs
index 7cefb615d03..345bec345d1 100644
--- a/library/coretests/tests/ptr.rs
+++ b/library/coretests/tests/ptr.rs
@@ -42,11 +42,11 @@ fn test() {
         let mut v1 = vec![0u16, 0u16, 0u16];
 
         copy(v0.as_ptr().offset(1), v1.as_mut_ptr().offset(1), 1);
-        assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16));
+        assert!(v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16);
         copy(v0.as_ptr().offset(2), v1.as_mut_ptr(), 1);
-        assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16));
+        assert!(v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16);
         copy(v0.as_ptr(), v1.as_mut_ptr().offset(2), 1);
-        assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16));
+        assert!(v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16);
     }
 }
 
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 28f16da1ed8..e3810030ded 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -14,7 +14,7 @@ use crate::os::unix::fs::symlink as junction_point;
 use crate::os::windows::fs::{OpenOptionsExt, junction_point, symlink_dir, symlink_file};
 use crate::path::Path;
 use crate::sync::Arc;
-use crate::sys_common::io::test::{TempDir, tmpdir};
+use crate::test_helpers::{TempDir, tmpdir};
 use crate::time::{Duration, Instant, SystemTime};
 use crate::{env, str, thread};
 
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index b2ffeb0f95d..606099c8bc6 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -153,7 +153,7 @@ impl<T> Cursor<T> {
     /// let reference = buff.get_mut();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")]
+    #[rustc_const_stable(feature = "const_mut_cursor", since = "CURRENT_RUSTC_VERSION")]
     pub const fn get_mut(&mut self) -> &mut T {
         &mut self.inner
     }
@@ -201,7 +201,7 @@ impl<T> Cursor<T> {
     /// assert_eq!(buff.position(), 4);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")]
+    #[rustc_const_stable(feature = "const_mut_cursor", since = "CURRENT_RUSTC_VERSION")]
     pub const fn set_position(&mut self, pos: u64) {
         self.pos = pos;
     }
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index cfd03b8e3d6..0ffad2c27a4 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -344,7 +344,7 @@ pub mod prelude;
 mod stdio;
 mod util;
 
-const DEFAULT_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
+const DEFAULT_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE;
 
 pub(crate) use stdio::cleanup;
 
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 7c18226874c..954a4182fbd 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -739,27 +739,4 @@ mod sealed {
 
 #[cfg(test)]
 #[allow(dead_code)] // Not used in all configurations.
-pub(crate) mod test_helpers {
-    /// Test-only replacement for `rand::thread_rng()`, which is unusable for
-    /// us, as we want to allow running stdlib tests on tier-3 targets which may
-    /// not have `getrandom` support.
-    ///
-    /// Does a bit of a song and dance to ensure that the seed is different on
-    /// each call (as some tests sadly rely on this), but doesn't try that hard.
-    ///
-    /// This is duplicated in the `core`, `alloc` test suites (as well as
-    /// `std`'s integration tests), but figuring out a mechanism to share these
-    /// seems far more painful than copy-pasting a 7 line function a couple
-    /// times, given that even under a perma-unstable feature, I don't think we
-    /// want to expose types from `rand` from `std`.
-    #[track_caller]
-    pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
-        use core::hash::{BuildHasher, Hash, Hasher};
-        let mut hasher = crate::hash::RandomState::new().build_hasher();
-        core::panic::Location::caller().hash(&mut hasher);
-        let hc64 = hasher.finish();
-        let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
-        let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
-        rand::SeedableRng::from_seed(seed)
-    }
-}
+pub(crate) mod test_helpers;
diff --git a/library/std/src/net/test.rs b/library/std/src/net/test.rs
index d318d457f35..a5c3983cd89 100644
--- a/library/std/src/net/test.rs
+++ b/library/std/src/net/test.rs
@@ -5,14 +5,15 @@ use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToS
 use crate::sync::atomic::{AtomicUsize, Ordering};
 
 static PORT: AtomicUsize = AtomicUsize::new(0);
+const BASE_PORT: u16 = 19600;
 
 pub fn next_test_ip4() -> SocketAddr {
-    let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + base_port();
+    let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + BASE_PORT;
     SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port))
 }
 
 pub fn next_test_ip6() -> SocketAddr {
-    let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + base_port();
+    let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + BASE_PORT;
     SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), port, 0, 0))
 }
 
@@ -30,31 +31,3 @@ pub fn tsa<A: ToSocketAddrs>(a: A) -> Result<Vec<SocketAddr>, String> {
         Err(e) => Err(e.to_string()),
     }
 }
-
-// The bots run multiple builds at the same time, and these builds
-// all want to use ports. This function figures out which workspace
-// it is running in and assigns a port range based on it.
-fn base_port() -> u16 {
-    let cwd = if cfg!(target_env = "sgx") {
-        String::from("sgx")
-    } else {
-        env::current_dir().unwrap().into_os_string().into_string().unwrap()
-    };
-    let dirs = [
-        "32-opt",
-        "32-nopt",
-        "musl-64-opt",
-        "cross-opt",
-        "64-opt",
-        "64-nopt",
-        "64-opt-vg",
-        "64-debug-opt",
-        "all-opt",
-        "snap3",
-        "dist",
-        "sgx",
-    ];
-    dirs.iter().enumerate().find(|&(_, dir)| cwd.contains(dir)).map(|p| p.0).unwrap_or(0) as u16
-        * 1000
-        + 19600
-}
diff --git a/library/std/src/os/unix/fs/tests.rs b/library/std/src/os/unix/fs/tests.rs
index 67f607bd468..db9621c8c20 100644
--- a/library/std/src/os/unix/fs/tests.rs
+++ b/library/std/src/os/unix/fs/tests.rs
@@ -3,7 +3,7 @@ use super::*;
 #[test]
 fn read_vectored_at() {
     let msg = b"preadv is working!";
-    let dir = crate::sys_common::io::test::tmpdir();
+    let dir = crate::test_helpers::tmpdir();
 
     let filename = dir.join("preadv.txt");
     {
@@ -31,7 +31,7 @@ fn read_vectored_at() {
 #[test]
 fn write_vectored_at() {
     let msg = b"pwritev is not working!";
-    let dir = crate::sys_common::io::test::tmpdir();
+    let dir = crate::test_helpers::tmpdir();
 
     let filename = dir.join("preadv.txt");
     {
diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs
index 21e2176185d..0398a535eb5 100644
--- a/library/std/src/os/unix/net/tests.rs
+++ b/library/std/src/os/unix/net/tests.rs
@@ -7,7 +7,7 @@ use crate::os::android::net::{SocketAddrExt, UnixSocketExt};
 use crate::os::linux::net::{SocketAddrExt, UnixSocketExt};
 #[cfg(any(target_os = "android", target_os = "linux"))]
 use crate::os::unix::io::AsRawFd;
-use crate::sys_common::io::test::tmpdir;
+use crate::test_helpers::tmpdir;
 use crate::thread;
 use crate::time::Duration;
 
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index 1323aba38b7..69273d863eb 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -391,154 +391,6 @@ fn test_interior_nul_in_env_value_is_error() {
     }
 }
 
-/// Tests that process creation flags work by debugging a process.
-/// Other creation flags make it hard or impossible to detect
-/// behavioral changes in the process.
-#[test]
-#[cfg(windows)]
-fn test_creation_flags() {
-    use crate::os::windows::process::CommandExt;
-    use crate::sys::c::{BOOL, INFINITE};
-    #[repr(C)]
-    struct DEBUG_EVENT {
-        pub event_code: u32,
-        pub process_id: u32,
-        pub thread_id: u32,
-        // This is a union in the real struct, but we don't
-        // need this data for the purposes of this test.
-        pub _junk: [u8; 164],
-    }
-
-    extern "system" {
-        fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: u32) -> BOOL;
-        fn ContinueDebugEvent(dwProcessId: u32, dwThreadId: u32, dwContinueStatus: u32) -> BOOL;
-    }
-
-    const DEBUG_PROCESS: u32 = 1;
-    const EXIT_PROCESS_DEBUG_EVENT: u32 = 5;
-    const DBG_EXCEPTION_NOT_HANDLED: u32 = 0x80010001;
-
-    let mut child = Command::new("cmd")
-        .creation_flags(DEBUG_PROCESS)
-        .stdin(Stdio::piped())
-        .stdout(Stdio::null())
-        .stderr(Stdio::null())
-        .spawn()
-        .unwrap();
-    child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap();
-    let mut events = 0;
-    let mut event = DEBUG_EVENT { event_code: 0, process_id: 0, thread_id: 0, _junk: [0; 164] };
-    loop {
-        if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 {
-            panic!("WaitForDebugEvent failed!");
-        }
-        events += 1;
-
-        if event.event_code == EXIT_PROCESS_DEBUG_EVENT {
-            break;
-        }
-
-        if unsafe {
-            ContinueDebugEvent(event.process_id, event.thread_id, DBG_EXCEPTION_NOT_HANDLED)
-        } == 0
-        {
-            panic!("ContinueDebugEvent failed!");
-        }
-    }
-    assert!(events > 0);
-}
-
-/// Tests proc thread attributes by spawning a process with a custom parent process,
-/// then comparing the parent process ID with the expected parent process ID.
-#[test]
-#[cfg(windows)]
-fn test_proc_thread_attributes() {
-    use crate::mem;
-    use crate::os::windows::io::AsRawHandle;
-    use crate::os::windows::process::{CommandExt, ProcThreadAttributeList};
-    use crate::sys::c::{BOOL, CloseHandle, HANDLE};
-    use crate::sys::cvt;
-
-    #[repr(C)]
-    #[allow(non_snake_case)]
-    struct PROCESSENTRY32W {
-        dwSize: u32,
-        cntUsage: u32,
-        th32ProcessID: u32,
-        th32DefaultHeapID: usize,
-        th32ModuleID: u32,
-        cntThreads: u32,
-        th32ParentProcessID: u32,
-        pcPriClassBase: i32,
-        dwFlags: u32,
-        szExeFile: [u16; 260],
-    }
-
-    extern "system" {
-        fn CreateToolhelp32Snapshot(dwflags: u32, th32processid: u32) -> HANDLE;
-        fn Process32First(hsnapshot: HANDLE, lppe: *mut PROCESSENTRY32W) -> BOOL;
-        fn Process32Next(hsnapshot: HANDLE, lppe: *mut PROCESSENTRY32W) -> BOOL;
-    }
-
-    const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
-    const TH32CS_SNAPPROCESS: u32 = 0x00000002;
-
-    struct ProcessDropGuard(crate::process::Child);
-
-    impl Drop for ProcessDropGuard {
-        fn drop(&mut self) {
-            let _ = self.0.kill();
-        }
-    }
-
-    let mut parent = Command::new("cmd");
-    parent.stdout(Stdio::null()).stderr(Stdio::null());
-
-    let parent = ProcessDropGuard(parent.spawn().unwrap());
-
-    let mut child_cmd = Command::new("cmd");
-    child_cmd.stdout(Stdio::null()).stderr(Stdio::null());
-
-    let parent_process_handle = parent.0.as_raw_handle();
-
-    let mut attribute_list = ProcThreadAttributeList::build()
-        .attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_process_handle)
-        .finish()
-        .unwrap();
-
-    let child = ProcessDropGuard(child_cmd.spawn_with_attributes(&mut attribute_list).unwrap());
-
-    let h_snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
-
-    let mut process_entry = PROCESSENTRY32W {
-        dwSize: mem::size_of::<PROCESSENTRY32W>() as u32,
-        cntUsage: 0,
-        th32ProcessID: 0,
-        th32DefaultHeapID: 0,
-        th32ModuleID: 0,
-        cntThreads: 0,
-        th32ParentProcessID: 0,
-        pcPriClassBase: 0,
-        dwFlags: 0,
-        szExeFile: [0; 260],
-    };
-
-    unsafe { cvt(Process32First(h_snapshot, &mut process_entry as *mut _)) }.unwrap();
-
-    loop {
-        if child.0.id() == process_entry.th32ProcessID {
-            break;
-        }
-        unsafe { cvt(Process32Next(h_snapshot, &mut process_entry as *mut _)) }.unwrap();
-    }
-
-    unsafe { cvt(CloseHandle(h_snapshot)) }.unwrap();
-
-    assert_eq!(parent.0.id(), process_entry.th32ParentProcessID);
-
-    drop(child)
-}
-
 #[test]
 fn test_command_implements_send_sync() {
     fn take_send_sync_type<T: Send + Sync>(_: T) {}
@@ -697,7 +549,7 @@ fn debug_print() {
 #[test]
 #[cfg(windows)]
 fn run_bat_script() {
-    let tempdir = crate::sys_common::io::test::tmpdir();
+    let tempdir = crate::test_helpers::tmpdir();
     let script_path = tempdir.join("hello.cmd");
 
     crate::fs::write(&script_path, "@echo Hello, %~1!").unwrap();
@@ -716,7 +568,7 @@ fn run_bat_script() {
 #[test]
 #[cfg(windows)]
 fn run_canonical_bat_script() {
-    let tempdir = crate::sys_common::io::test::tmpdir();
+    let tempdir = crate::test_helpers::tmpdir();
     let script_path = tempdir.join("hello.cmd");
 
     crate::fs::write(&script_path, "@echo Hello, %~1!").unwrap();
diff --git a/library/std/src/sys/pal/hermit/io.rs b/library/std/src/sys/io/io_slice/iovec.rs
index 0424a1ac55a..072191315f7 100644
--- a/library/std/src/sys/pal/hermit/io.rs
+++ b/library/std/src/sys/io/io_slice/iovec.rs
@@ -1,8 +1,13 @@
-use hermit_abi::{c_void, iovec};
+#[cfg(target_os = "hermit")]
+use hermit_abi::iovec;
+#[cfg(target_family = "unix")]
+use libc::iovec;
 
+use crate::ffi::c_void;
 use crate::marker::PhantomData;
-use crate::os::hermit::io::{AsFd, AsRawFd};
 use crate::slice;
+#[cfg(target_os = "solid_asp3")]
+use crate::sys::pal::abi::sockets::iovec;
 
 #[derive(Copy, Clone)]
 #[repr(transparent)]
@@ -80,8 +85,3 @@ impl<'a> IoSliceMut<'a> {
         unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
     }
 }
-
-pub fn is_terminal(fd: &impl AsFd) -> bool {
-    let fd = fd.as_fd();
-    hermit_abi::isatty(fd.as_raw_fd())
-}
diff --git a/library/std/src/sys/pal/unsupported/io.rs b/library/std/src/sys/io/io_slice/unsupported.rs
index 604735d32d5..1572cac6cd7 100644
--- a/library/std/src/sys/pal/unsupported/io.rs
+++ b/library/std/src/sys/io/io_slice/unsupported.rs
@@ -50,7 +50,3 @@ impl<'a> IoSliceMut<'a> {
         self.0
     }
 }
-
-pub fn is_terminal<T>(_: &T) -> bool {
-    false
-}
diff --git a/library/std/src/sys/pal/wasi/io.rs b/library/std/src/sys/io/io_slice/wasi.rs
index 57f81bc6257..87acbbd924e 100644
--- a/library/std/src/sys/pal/wasi/io.rs
+++ b/library/std/src/sys/io/io_slice/wasi.rs
@@ -1,7 +1,4 @@
-#![forbid(unsafe_op_in_unsafe_fn)]
-
 use crate::marker::PhantomData;
-use crate::os::fd::{AsFd, AsRawFd};
 use crate::slice;
 
 #[derive(Copy, Clone)]
@@ -77,8 +74,3 @@ impl<'a> IoSliceMut<'a> {
         unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) }
     }
 }
-
-pub fn is_terminal(fd: &impl AsFd) -> bool {
-    let fd = fd.as_fd();
-    unsafe { libc::isatty(fd.as_raw_fd()) != 0 }
-}
diff --git a/library/std/src/sys/pal/solid/io.rs b/library/std/src/sys/io/io_slice/windows.rs
index 9ef4b7049b6..c3d8ec87c19 100644
--- a/library/std/src/sys/pal/solid/io.rs
+++ b/library/std/src/sys/io/io_slice/windows.rs
@@ -1,86 +1,82 @@
-use libc::c_void;
-
-use super::abi::sockets::iovec;
 use crate::marker::PhantomData;
 use crate::slice;
+use crate::sys::c;
 
 #[derive(Copy, Clone)]
 #[repr(transparent)]
 pub struct IoSlice<'a> {
-    vec: iovec,
+    vec: c::WSABUF,
     _p: PhantomData<&'a [u8]>,
 }
 
 impl<'a> IoSlice<'a> {
     #[inline]
     pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
+        assert!(buf.len() <= u32::MAX as usize);
         IoSlice {
-            vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() },
+            vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_ptr() as *mut u8 },
             _p: PhantomData,
         }
     }
 
     #[inline]
     pub fn advance(&mut self, n: usize) {
-        if self.vec.iov_len < n {
+        if (self.vec.len as usize) < n {
             panic!("advancing IoSlice beyond its length");
         }
 
         unsafe {
-            self.vec.iov_len -= n;
-            self.vec.iov_base = self.vec.iov_base.add(n);
+            self.vec.len -= n as u32;
+            self.vec.buf = self.vec.buf.add(n);
         }
     }
 
     #[inline]
     pub const fn as_slice(&self) -> &'a [u8] {
-        unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
+        unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) }
     }
 }
 
 #[repr(transparent)]
 pub struct IoSliceMut<'a> {
-    vec: iovec,
+    vec: c::WSABUF,
     _p: PhantomData<&'a mut [u8]>,
 }
 
 impl<'a> IoSliceMut<'a> {
     #[inline]
     pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
+        assert!(buf.len() <= u32::MAX as usize);
         IoSliceMut {
-            vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() },
+            vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_mut_ptr() },
             _p: PhantomData,
         }
     }
 
     #[inline]
     pub fn advance(&mut self, n: usize) {
-        if self.vec.iov_len < n {
+        if (self.vec.len as usize) < n {
             panic!("advancing IoSliceMut beyond its length");
         }
 
         unsafe {
-            self.vec.iov_len -= n;
-            self.vec.iov_base = self.vec.iov_base.add(n);
+            self.vec.len -= n as u32;
+            self.vec.buf = self.vec.buf.add(n);
         }
     }
 
     #[inline]
     pub fn as_slice(&self) -> &[u8] {
-        unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
+        unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) }
     }
 
     #[inline]
     pub const fn into_slice(self) -> &'a mut [u8] {
-        unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
+        unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) }
     }
 
     #[inline]
     pub fn as_mut_slice(&mut self) -> &mut [u8] {
-        unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
+        unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) }
     }
 }
-
-pub fn is_terminal<T>(_: &T) -> bool {
-    false
-}
diff --git a/library/std/src/sys/io/is_terminal/hermit.rs b/library/std/src/sys/io/is_terminal/hermit.rs
new file mode 100644
index 00000000000..61bdb6f0a54
--- /dev/null
+++ b/library/std/src/sys/io/is_terminal/hermit.rs
@@ -0,0 +1,6 @@
+use crate::os::fd::{AsFd, AsRawFd};
+
+pub fn is_terminal(fd: &impl AsFd) -> bool {
+    let fd = fd.as_fd();
+    hermit_abi::isatty(fd.as_raw_fd())
+}
diff --git a/library/std/src/sys/io/is_terminal/isatty.rs b/library/std/src/sys/io/is_terminal/isatty.rs
new file mode 100644
index 00000000000..6e0b46211b9
--- /dev/null
+++ b/library/std/src/sys/io/is_terminal/isatty.rs
@@ -0,0 +1,6 @@
+use crate::os::fd::{AsFd, AsRawFd};
+
+pub fn is_terminal(fd: &impl AsFd) -> bool {
+    let fd = fd.as_fd();
+    unsafe { libc::isatty(fd.as_raw_fd()) != 0 }
+}
diff --git a/library/std/src/sys/io/is_terminal/unsupported.rs b/library/std/src/sys/io/is_terminal/unsupported.rs
new file mode 100644
index 00000000000..cee4add32fb
--- /dev/null
+++ b/library/std/src/sys/io/is_terminal/unsupported.rs
@@ -0,0 +1,3 @@
+pub fn is_terminal<T>(_: &T) -> bool {
+    false
+}
diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/io/is_terminal/windows.rs
index f2865d2ffc1..3ec18fb47b9 100644
--- a/library/std/src/sys/pal/windows/io.rs
+++ b/library/std/src/sys/io/is_terminal/windows.rs
@@ -1,90 +1,8 @@
-use core::ffi::c_void;
-
-use crate::marker::PhantomData;
+use crate::ffi::c_void;
 use crate::mem::size_of;
 use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle};
-use crate::slice;
 use crate::sys::c;
 
-#[derive(Copy, Clone)]
-#[repr(transparent)]
-pub struct IoSlice<'a> {
-    vec: c::WSABUF,
-    _p: PhantomData<&'a [u8]>,
-}
-
-impl<'a> IoSlice<'a> {
-    #[inline]
-    pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
-        assert!(buf.len() <= u32::MAX as usize);
-        IoSlice {
-            vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_ptr() as *mut u8 },
-            _p: PhantomData,
-        }
-    }
-
-    #[inline]
-    pub fn advance(&mut self, n: usize) {
-        if (self.vec.len as usize) < n {
-            panic!("advancing IoSlice beyond its length");
-        }
-
-        unsafe {
-            self.vec.len -= n as u32;
-            self.vec.buf = self.vec.buf.add(n);
-        }
-    }
-
-    #[inline]
-    pub const fn as_slice(&self) -> &'a [u8] {
-        unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) }
-    }
-}
-
-#[repr(transparent)]
-pub struct IoSliceMut<'a> {
-    vec: c::WSABUF,
-    _p: PhantomData<&'a mut [u8]>,
-}
-
-impl<'a> IoSliceMut<'a> {
-    #[inline]
-    pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
-        assert!(buf.len() <= u32::MAX as usize);
-        IoSliceMut {
-            vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_mut_ptr() },
-            _p: PhantomData,
-        }
-    }
-
-    #[inline]
-    pub fn advance(&mut self, n: usize) {
-        if (self.vec.len as usize) < n {
-            panic!("advancing IoSliceMut beyond its length");
-        }
-
-        unsafe {
-            self.vec.len -= n as u32;
-            self.vec.buf = self.vec.buf.add(n);
-        }
-    }
-
-    #[inline]
-    pub fn as_slice(&self) -> &[u8] {
-        unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) }
-    }
-
-    #[inline]
-    pub const fn into_slice(self) -> &'a mut [u8] {
-        unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) }
-    }
-
-    #[inline]
-    pub fn as_mut_slice(&mut self) -> &mut [u8] {
-        unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) }
-    }
-}
-
 pub fn is_terminal(h: &impl AsHandle) -> bool {
     handle_is_console(h.as_handle())
 }
diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs
new file mode 100644
index 00000000000..e00b479109f
--- /dev/null
+++ b/library/std/src/sys/io/mod.rs
@@ -0,0 +1,44 @@
+#![forbid(unsafe_op_in_unsafe_fn)]
+
+mod io_slice {
+    cfg_if::cfg_if! {
+        if #[cfg(any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3"))] {
+            mod iovec;
+            pub use iovec::*;
+        } else if #[cfg(target_os = "windows")] {
+            mod windows;
+            pub use windows::*;
+        } else if #[cfg(target_os = "wasi")] {
+            mod wasi;
+            pub use wasi::*;
+        } else {
+            mod unsupported;
+            pub use unsupported::*;
+        }
+    }
+}
+
+mod is_terminal {
+    cfg_if::cfg_if! {
+        if #[cfg(any(target_family = "unix", target_os = "wasi"))] {
+            mod isatty;
+            pub use isatty::*;
+        } else if #[cfg(target_os = "windows")] {
+            mod windows;
+            pub use windows::*;
+        } else if #[cfg(target_os = "hermit")] {
+            mod hermit;
+            pub use hermit::*;
+        } else {
+            mod unsupported;
+            pub use unsupported::*;
+        }
+    }
+}
+
+pub use io_slice::{IoSlice, IoSliceMut};
+pub use is_terminal::is_terminal;
+
+// Bare metal platforms usually have very small amounts of RAM
+// (in the order of hundreds of KB)
+pub const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") { 512 } else { 8 * 1024 };
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 39a0bc6e337..1032fcba5e2 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -12,6 +12,7 @@ pub mod anonymous_pipe;
 pub mod backtrace;
 pub mod cmath;
 pub mod exit_guard;
+pub mod io;
 pub mod net;
 pub mod os_str;
 pub mod path;
diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs
new file mode 100644
index 00000000000..87e6106468f
--- /dev/null
+++ b/library/std/src/sys/net/connection/uefi/mod.rs
@@ -0,0 +1,369 @@
+use crate::fmt;
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
+use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+use crate::sys::unsupported;
+use crate::time::Duration;
+
+pub struct TcpStream(!);
+
+impl TcpStream {
+    pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+        unsupported()
+    }
+
+    pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+        unsupported()
+    }
+
+    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0
+    }
+
+    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn is_read_vectored(&self) -> bool {
+        self.0
+    }
+
+    pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn is_write_vectored(&self) -> bool {
+        self.0
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        self.0
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        self.0
+    }
+
+    pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpStream> {
+        self.0
+    }
+
+    pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        self.0
+    }
+
+    pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        self.0
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        self.0
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.0
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+}
+
+impl fmt::Debug for TcpStream {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0
+    }
+}
+
+pub struct TcpListener(!);
+
+impl TcpListener {
+    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+        unsupported()
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        self.0
+    }
+
+    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+        self.0
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpListener> {
+        self.0
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        self.0
+    }
+
+    pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn only_v6(&self) -> io::Result<bool> {
+        self.0
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.0
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+}
+
+impl fmt::Debug for TcpListener {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0
+    }
+}
+
+pub struct UdpSocket(!);
+
+impl UdpSocket {
+    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+        unsupported()
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        self.0
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        self.0
+    }
+
+    pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.0
+    }
+
+    pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.0
+    }
+
+    pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn duplicate(&self) -> io::Result<UdpSocket> {
+        self.0
+    }
+
+    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0
+    }
+
+    pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn broadcast(&self) -> io::Result<bool> {
+        self.0
+    }
+
+    pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+        self.0
+    }
+
+    pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+        self.0
+    }
+
+    pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+        self.0
+    }
+
+    pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        self.0
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.0
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+        self.0
+    }
+}
+
+impl fmt::Debug for UdpSocket {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0
+    }
+}
+
+pub struct LookupHost(!);
+
+impl LookupHost {
+    pub fn port(&self) -> u16 {
+        self.0
+    }
+}
+
+impl Iterator for LookupHost {
+    type Item = SocketAddr;
+    fn next(&mut self) -> Option<SocketAddr> {
+        self.0
+    }
+}
+
+impl TryFrom<&str> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(_v: &str) -> io::Result<LookupHost> {
+        unsupported()
+    }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+        unsupported()
+    }
+}
+
+#[allow(nonstandard_style)]
+pub mod netc {
+    pub const AF_INET: u8 = 0;
+    pub const AF_INET6: u8 = 1;
+    pub type sa_family_t = u8;
+
+    #[derive(Copy, Clone)]
+    pub struct in_addr {
+        pub s_addr: u32,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr_in {
+        #[allow(dead_code)]
+        pub sin_family: sa_family_t,
+        pub sin_port: u16,
+        pub sin_addr: in_addr,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct in6_addr {
+        pub s6_addr: [u8; 16],
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr_in6 {
+        #[allow(dead_code)]
+        pub sin6_family: sa_family_t,
+        pub sin6_port: u16,
+        pub sin6_addr: in6_addr,
+        pub sin6_flowinfo: u32,
+        pub sin6_scope_id: u32,
+    }
+}
diff --git a/library/std/src/sys/net/mod.rs b/library/std/src/sys/net/mod.rs
index 5aa197fbc0d..646679a1cc8 100644
--- a/library/std/src/sys/net/mod.rs
+++ b/library/std/src/sys/net/mod.rs
@@ -25,6 +25,11 @@ cfg_if::cfg_if! {
             mod xous;
             pub use xous::*;
         }
+    } else if #[cfg(target_os = "uefi")] {
+        mod connection {
+            mod uefi;
+            pub use uefi::*;
+        }
     } else {
         mod connection {
             mod unsupported;
diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs
index 032007aa4dc..3d555ad5050 100644
--- a/library/std/src/sys/pal/hermit/mod.rs
+++ b/library/std/src/sys/pal/hermit/mod.rs
@@ -23,7 +23,6 @@ pub mod env;
 pub mod fd;
 pub mod fs;
 pub mod futex;
-pub mod io;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs
index 0f5935d0c71..9a04fa4b97e 100644
--- a/library/std/src/sys/pal/sgx/mod.rs
+++ b/library/std/src/sys/pal/sgx/mod.rs
@@ -14,8 +14,6 @@ pub mod env;
 pub mod fd;
 #[path = "../unsupported/fs.rs"]
 pub mod fs;
-#[path = "../unsupported/io.rs"]
-pub mod io;
 mod libunwind_integration;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
diff --git a/library/std/src/sys/pal/sgx/stdio.rs b/library/std/src/sys/pal/sgx/stdio.rs
index 2e680e740fd..e79a3d971c6 100644
--- a/library/std/src/sys/pal/sgx/stdio.rs
+++ b/library/std/src/sys/pal/sgx/stdio.rs
@@ -62,7 +62,7 @@ impl io::Write for Stderr {
     }
 }
 
-pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
+pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE;
 
 pub fn is_ebadf(err: &io::Error) -> bool {
     // FIXME: Rust normally maps Unix EBADF to `Uncategorized`
diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs
index caf848a4e9b..06af7bfade0 100644
--- a/library/std/src/sys/pal/solid/mod.rs
+++ b/library/std/src/sys/pal/solid/mod.rs
@@ -23,7 +23,6 @@ pub mod env;
 // `crate::sys::error`
 pub(crate) mod error;
 pub mod fs;
-pub mod io;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs
index a9904e66664..f850fefc8f2 100644
--- a/library/std/src/sys/pal/teeos/mod.rs
+++ b/library/std/src/sys/pal/teeos/mod.rs
@@ -13,8 +13,6 @@ pub mod env;
 //pub mod fd;
 #[path = "../unsupported/fs.rs"]
 pub mod fs;
-#[path = "../unsupported/io.rs"]
-pub mod io;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index 07025a304bf..4766e2ef0a9 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -17,8 +17,6 @@ pub mod args;
 pub mod env;
 pub mod fs;
 pub mod helpers;
-#[path = "../unsupported/io.rs"]
-pub mod io;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
diff --git a/library/std/src/sys/pal/unix/io.rs b/library/std/src/sys/pal/unix/io.rs
deleted file mode 100644
index 0d5a152dc0d..00000000000
--- a/library/std/src/sys/pal/unix/io.rs
+++ /dev/null
@@ -1,87 +0,0 @@
-use libc::{c_void, iovec};
-
-use crate::marker::PhantomData;
-use crate::os::fd::{AsFd, AsRawFd};
-use crate::slice;
-
-#[derive(Copy, Clone)]
-#[repr(transparent)]
-pub struct IoSlice<'a> {
-    vec: iovec,
-    _p: PhantomData<&'a [u8]>,
-}
-
-impl<'a> IoSlice<'a> {
-    #[inline]
-    pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
-        IoSlice {
-            vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() },
-            _p: PhantomData,
-        }
-    }
-
-    #[inline]
-    pub fn advance(&mut self, n: usize) {
-        if self.vec.iov_len < n {
-            panic!("advancing IoSlice beyond its length");
-        }
-
-        unsafe {
-            self.vec.iov_len -= n;
-            self.vec.iov_base = self.vec.iov_base.add(n);
-        }
-    }
-
-    #[inline]
-    pub const fn as_slice(&self) -> &'a [u8] {
-        unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
-    }
-}
-
-#[repr(transparent)]
-pub struct IoSliceMut<'a> {
-    vec: iovec,
-    _p: PhantomData<&'a mut [u8]>,
-}
-
-impl<'a> IoSliceMut<'a> {
-    #[inline]
-    pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
-        IoSliceMut {
-            vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() },
-            _p: PhantomData,
-        }
-    }
-
-    #[inline]
-    pub fn advance(&mut self, n: usize) {
-        if self.vec.iov_len < n {
-            panic!("advancing IoSliceMut beyond its length");
-        }
-
-        unsafe {
-            self.vec.iov_len -= n;
-            self.vec.iov_base = self.vec.iov_base.add(n);
-        }
-    }
-
-    #[inline]
-    pub fn as_slice(&self) -> &[u8] {
-        unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
-    }
-
-    #[inline]
-    pub const fn into_slice(self) -> &'a mut [u8] {
-        unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
-    }
-
-    #[inline]
-    pub fn as_mut_slice(&mut self) -> &mut [u8] {
-        unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
-    }
-}
-
-pub fn is_terminal(fd: &impl AsFd) -> bool {
-    let fd = fd.as_fd();
-    unsafe { libc::isatty(fd.as_raw_fd()) != 0 }
-}
diff --git a/library/std/src/sys/pal/unix/kernel_copy/tests.rs b/library/std/src/sys/pal/unix/kernel_copy/tests.rs
index 1350d743ff6..54d8f8ed2ed 100644
--- a/library/std/src/sys/pal/unix/kernel_copy/tests.rs
+++ b/library/std/src/sys/pal/unix/kernel_copy/tests.rs
@@ -2,7 +2,7 @@ use crate::fs::OpenOptions;
 use crate::io;
 use crate::io::{BufRead, Read, Result, Seek, SeekFrom, Write};
 use crate::os::unix::io::AsRawFd;
-use crate::sys_common::io::test::tmpdir;
+use crate::test_helpers::tmpdir;
 
 #[test]
 fn copy_specialization() -> Result<()> {
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index 6862399b942..027df6c5691 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -11,7 +11,6 @@ pub mod env;
 pub mod fd;
 pub mod fs;
 pub mod futex;
-pub mod io;
 #[cfg(any(target_os = "linux", target_os = "android"))]
 pub mod kernel_copy;
 #[cfg(target_os = "linux")]
diff --git a/library/std/src/sys/pal/unix/stdio.rs b/library/std/src/sys/pal/unix/stdio.rs
index 97e75f1b5b6..8c2f61a40de 100644
--- a/library/std/src/sys/pal/unix/stdio.rs
+++ b/library/std/src/sys/pal/unix/stdio.rs
@@ -92,7 +92,7 @@ pub fn is_ebadf(err: &io::Error) -> bool {
     err.raw_os_error() == Some(libc::EBADF as i32)
 }
 
-pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
+pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE;
 
 pub fn panic_output() -> Option<impl io::Write> {
     Some(Stderr::new())
diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs
index 4941dd4918c..b1aaeb1b4c8 100644
--- a/library/std/src/sys/pal/unsupported/mod.rs
+++ b/library/std/src/sys/pal/unsupported/mod.rs
@@ -3,7 +3,6 @@
 pub mod args;
 pub mod env;
 pub mod fs;
-pub mod io;
 pub mod os;
 pub mod pipe;
 pub mod process;
diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs
index 312ad28ab51..f4588a60ea9 100644
--- a/library/std/src/sys/pal/wasi/mod.rs
+++ b/library/std/src/sys/pal/wasi/mod.rs
@@ -20,7 +20,6 @@ pub mod fs;
 #[allow(unused)]
 #[path = "../wasm/atomics/futex.rs"]
 pub mod futex;
-pub mod io;
 
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
diff --git a/library/std/src/sys/pal/wasi/stdio.rs b/library/std/src/sys/pal/wasi/stdio.rs
index ca49f871e19..d08b772e5fc 100644
--- a/library/std/src/sys/pal/wasi/stdio.rs
+++ b/library/std/src/sys/pal/wasi/stdio.rs
@@ -101,7 +101,7 @@ impl io::Write for Stderr {
     }
 }
 
-pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
+pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE;
 
 pub fn is_ebadf(err: &io::Error) -> bool {
     err.raw_os_error() == Some(wasi::ERRNO_BADF.raw().into())
diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs
index 234e946d3b8..72c9742b2e5 100644
--- a/library/std/src/sys/pal/wasip2/mod.rs
+++ b/library/std/src/sys/pal/wasip2/mod.rs
@@ -17,8 +17,6 @@ pub mod fs;
 #[allow(unused)]
 #[path = "../wasm/atomics/futex.rs"]
 pub mod futex;
-#[path = "../wasi/io.rs"]
-pub mod io;
 
 #[path = "../wasi/os.rs"]
 pub mod os;
diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs
index 1280f353200..32d59c4d0f7 100644
--- a/library/std/src/sys/pal/wasm/mod.rs
+++ b/library/std/src/sys/pal/wasm/mod.rs
@@ -21,8 +21,6 @@ pub mod args;
 pub mod env;
 #[path = "../unsupported/fs.rs"]
 pub mod fs;
-#[path = "../unsupported/io.rs"]
-pub mod io;
 #[path = "../unsupported/os.rs"]
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index f9aa049ca9a..1eca346b76c 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -21,7 +21,6 @@ pub mod fs;
 #[cfg(not(target_vendor = "win7"))]
 pub mod futex;
 pub mod handle;
-pub mod io;
 pub mod os;
 pub mod pipe;
 pub mod process;
diff --git a/library/std/src/sys/pal/windows/process/tests.rs b/library/std/src/sys/pal/windows/process/tests.rs
index 1bcc5fa6b20..9a1eaf42fd9 100644
--- a/library/std/src/sys/pal/windows/process/tests.rs
+++ b/library/std/src/sys/pal/windows/process/tests.rs
@@ -158,7 +158,7 @@ fn windows_exe_resolver() {
     use super::resolve_exe;
     use crate::io;
     use crate::sys::fs::symlink;
-    use crate::sys_common::io::test::tmpdir;
+    use crate::test_helpers::tmpdir;
 
     let env_paths = || env::var_os("PATH");
 
diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs
index 8ba2b6e2f20..1bd0e67f371 100644
--- a/library/std/src/sys/pal/xous/mod.rs
+++ b/library/std/src/sys/pal/xous/mod.rs
@@ -5,8 +5,6 @@ pub mod args;
 pub mod env;
 #[path = "../unsupported/fs.rs"]
 pub mod fs;
-#[path = "../unsupported/io.rs"]
-pub mod io;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs
index 9e9ae861070..054c867f90d 100644
--- a/library/std/src/sys/pal/zkvm/mod.rs
+++ b/library/std/src/sys/pal/zkvm/mod.rs
@@ -16,8 +16,6 @@ pub mod args;
 pub mod env;
 #[path = "../unsupported/fs.rs"]
 pub mod fs;
-#[path = "../unsupported/io.rs"]
-pub mod io;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
diff --git a/library/std/src/sys/pal/zkvm/stdio.rs b/library/std/src/sys/pal/zkvm/stdio.rs
index dd218c8894c..5f1d06dd1d7 100644
--- a/library/std/src/sys/pal/zkvm/stdio.rs
+++ b/library/std/src/sys/pal/zkvm/stdio.rs
@@ -54,7 +54,7 @@ impl io::Write for Stderr {
     }
 }
 
-pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
+pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE;
 
 pub fn is_ebadf(_err: &io::Error) -> bool {
     true
diff --git a/library/std/src/sys_common/io.rs b/library/std/src/sys_common/io.rs
deleted file mode 100644
index 6f6f282d432..00000000000
--- a/library/std/src/sys_common/io.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-// Bare metal platforms usually have very small amounts of RAM
-// (in the order of hundreds of KB)
-pub const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") { 512 } else { 8 * 1024 };
-
-#[cfg(test)]
-#[allow(dead_code)] // not used on emscripten and wasi
-pub mod test {
-    use rand::RngCore;
-
-    use crate::path::{Path, PathBuf};
-    use crate::{env, fs, thread};
-
-    pub struct TempDir(PathBuf);
-
-    impl TempDir {
-        pub fn join(&self, path: &str) -> PathBuf {
-            let TempDir(ref p) = *self;
-            p.join(path)
-        }
-
-        pub fn path(&self) -> &Path {
-            let TempDir(ref p) = *self;
-            p
-        }
-    }
-
-    impl Drop for TempDir {
-        fn drop(&mut self) {
-            // Gee, seeing how we're testing the fs module I sure hope that we
-            // at least implement this correctly!
-            let TempDir(ref p) = *self;
-            let result = fs::remove_dir_all(p);
-            // Avoid panicking while panicking as this causes the process to
-            // immediately abort, without displaying test results.
-            if !thread::panicking() {
-                result.unwrap();
-            }
-        }
-    }
-
-    #[track_caller] // for `test_rng`
-    pub fn tmpdir() -> TempDir {
-        let p = env::temp_dir();
-        let mut r = crate::test_helpers::test_rng();
-        let ret = p.join(&format!("rust-{}", r.next_u32()));
-        fs::create_dir(&ret).unwrap();
-        TempDir(ret)
-    }
-}
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 959fbd4ca0a..4dc67d26bd8 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -21,7 +21,6 @@
 mod tests;
 
 pub mod fs;
-pub mod io;
 pub mod process;
 pub mod wstr;
 pub mod wtf8;
diff --git a/library/std/src/test_helpers.rs b/library/std/src/test_helpers.rs
new file mode 100644
index 00000000000..7c20f38c863
--- /dev/null
+++ b/library/std/src/test_helpers.rs
@@ -0,0 +1,65 @@
+use rand::{RngCore, SeedableRng};
+
+use crate::hash::{BuildHasher, Hash, Hasher, RandomState};
+use crate::panic::Location;
+use crate::path::{Path, PathBuf};
+use crate::{env, fs, thread};
+
+/// Test-only replacement for `rand::thread_rng()`, which is unusable for
+/// us, as we want to allow running stdlib tests on tier-3 targets which may
+/// not have `getrandom` support.
+///
+/// Does a bit of a song and dance to ensure that the seed is different on
+/// each call (as some tests sadly rely on this), but doesn't try that hard.
+///
+/// This is duplicated in the `core`, `alloc` test suites (as well as
+/// `std`'s integration tests), but figuring out a mechanism to share these
+/// seems far more painful than copy-pasting a 7 line function a couple
+/// times, given that even under a perma-unstable feature, I don't think we
+/// want to expose types from `rand` from `std`.
+#[track_caller]
+pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+    let mut hasher = RandomState::new().build_hasher();
+    Location::caller().hash(&mut hasher);
+    let hc64 = hasher.finish();
+    let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
+    let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+    SeedableRng::from_seed(seed)
+}
+
+pub struct TempDir(PathBuf);
+
+impl TempDir {
+    pub fn join(&self, path: &str) -> PathBuf {
+        let TempDir(ref p) = *self;
+        p.join(path)
+    }
+
+    pub fn path(&self) -> &Path {
+        let TempDir(ref p) = *self;
+        p
+    }
+}
+
+impl Drop for TempDir {
+    fn drop(&mut self) {
+        // Gee, seeing how we're testing the fs module I sure hope that we
+        // at least implement this correctly!
+        let TempDir(ref p) = *self;
+        let result = fs::remove_dir_all(p);
+        // Avoid panicking while panicking as this causes the process to
+        // immediately abort, without displaying test results.
+        if !thread::panicking() {
+            result.unwrap();
+        }
+    }
+}
+
+#[track_caller] // for `test_rng`
+pub fn tmpdir() -> TempDir {
+    let p = env::temp_dir();
+    let mut r = test_rng();
+    let ret = p.join(&format!("rust-{}", r.next_u32()));
+    fs::create_dir(&ret).unwrap();
+    TempDir(ret)
+}
diff --git a/library/std/tests/common/mod.rs b/library/std/tests/common/mod.rs
index 7cf70c725e4..1e8e4cced6c 100644
--- a/library/std/tests/common/mod.rs
+++ b/library/std/tests/common/mod.rs
@@ -18,7 +18,7 @@ pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
     rand::SeedableRng::from_seed(seed)
 }
 
-// Copied from std::sys_common::io
+// Copied from std::test_helpers
 pub(crate) struct TempDir(PathBuf);
 
 impl TempDir {
diff --git a/library/std/tests/istr.rs b/library/std/tests/istr.rs
index 9a127ae803e..e481872977a 100644
--- a/library/std/tests/istr.rs
+++ b/library/std/tests/istr.rs
@@ -5,7 +5,7 @@ fn test_stack_assign() {
     let t: String = "a".to_string();
     assert_eq!(s, t);
     let u: String = "b".to_string();
-    assert!((s != u));
+    assert!(s != u);
 }
 
 #[test]
@@ -19,7 +19,7 @@ fn test_heap_assign() {
     let t: String = "a big ol' string".to_string();
     assert_eq!(s, t);
     let u: String = "a bad ol' string".to_string();
-    assert!((s != u));
+    assert!(s != u);
 }
 
 #[test]
diff --git a/library/std/tests/seq-compare.rs b/library/std/tests/seq-compare.rs
index 221f1c7cabd..ec39c5b603c 100644
--- a/library/std/tests/seq-compare.rs
+++ b/library/std/tests/seq-compare.rs
@@ -1,15 +1,15 @@
 #[test]
 fn seq_compare() {
-    assert!(("hello".to_string() < "hellr".to_string()));
-    assert!(("hello ".to_string() > "hello".to_string()));
-    assert!(("hello".to_string() != "there".to_string()));
-    assert!((vec![1, 2, 3, 4] > vec![1, 2, 3]));
-    assert!((vec![1, 2, 3] < vec![1, 2, 3, 4]));
-    assert!((vec![1, 2, 4, 4] > vec![1, 2, 3, 4]));
-    assert!((vec![1, 2, 3, 4] < vec![1, 2, 4, 4]));
-    assert!((vec![1, 2, 3] <= vec![1, 2, 3]));
-    assert!((vec![1, 2, 3] <= vec![1, 2, 3, 3]));
-    assert!((vec![1, 2, 3, 4] > vec![1, 2, 3]));
+    assert!("hello".to_string() < "hellr".to_string());
+    assert!("hello ".to_string() > "hello".to_string());
+    assert!("hello".to_string() != "there".to_string());
+    assert!(vec![1, 2, 3, 4] > vec![1, 2, 3]);
+    assert!(vec![1, 2, 3] < vec![1, 2, 3, 4]);
+    assert!(vec![1, 2, 4, 4] > vec![1, 2, 3, 4]);
+    assert!(vec![1, 2, 3, 4] < vec![1, 2, 4, 4]);
+    assert!(vec![1, 2, 3] <= vec![1, 2, 3]);
+    assert!(vec![1, 2, 3] <= vec![1, 2, 3, 3]);
+    assert!(vec![1, 2, 3, 4] > vec![1, 2, 3]);
     assert_eq!(vec![1, 2, 3], vec![1, 2, 3]);
-    assert!((vec![1, 2, 3] != vec![1, 1, 3]));
+    assert!(vec![1, 2, 3] != vec![1, 1, 3]);
 }
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 0eb4080c053..dedcc139ae1 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -830,7 +830,8 @@ impl Step for Rustc {
         cargo.rustdocflag("--show-type-layout");
         // FIXME: `--generate-link-to-definition` tries to resolve cfged out code
         // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222
-        // cargo.rustdocflag("--generate-link-to-definition");
+        // If there is any bug, please comment out the next line.
+        cargo.rustdocflag("--generate-link-to-definition");
 
         compile::rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates);
         cargo.arg("-Zskip-rustdoc-fingerprint");
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 75fac88252b..620daec5114 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -582,7 +582,7 @@ impl Step for Rustdoc {
             if !target_compiler.is_snapshot(builder) {
                 panic!("rustdoc in stage 0 must be snapshot rustdoc");
             }
-            return builder.initial_rustc.with_file_name(exe("rustdoc", target_compiler.host));
+            return builder.initial_rustdoc.clone();
         }
         let target = target_compiler.host;
 
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 2dd83d5938e..4e097b67503 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -154,6 +154,7 @@ pub struct Build {
     targets: Vec<TargetSelection>,
 
     initial_rustc: PathBuf,
+    initial_rustdoc: PathBuf,
     initial_cargo: PathBuf,
     initial_lld: PathBuf,
     initial_relative_libdir: PathBuf,
@@ -354,6 +355,7 @@ impl Build {
             initial_lld,
             initial_relative_libdir,
             initial_rustc: config.initial_rustc.clone(),
+            initial_rustdoc: config.initial_rustc.with_file_name(exe("rustdoc", config.build)),
             initial_cargo: config.initial_cargo.clone(),
             initial_sysroot: config.initial_sysroot.clone(),
             local_rebuild: config.local_rebuild,
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index 60216395c2f..1902dcd3962 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -1,3 +1,8 @@
+//! Command Execution Module
+//!
+//! This module provides a structured way to execute and manage commands efficiently,
+//! ensuring controlled failure handling and output management.
+
 use std::ffi::OsStr;
 use std::fmt::{Debug, Formatter};
 use std::path::Path;
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index 6c9071b4191..03ec77f507e 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -56,9 +56,9 @@ ENV \
     CFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
     CXX_x86_64_fortanix_unknown_sgx=clang++-11 \
     CXXFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
-    AR_i686_unknown_freebsd=i686-unknown-freebsd13-ar \
-    CC_i686_unknown_freebsd=i686-unknown-freebsd13-clang \
-    CXX_i686_unknown_freebsd=i686-unknown-freebsd13-clang++ \
+    AR_i686_unknown_freebsd=i686-unknown-freebsd12-ar \
+    CC_i686_unknown_freebsd=i686-unknown-freebsd12-clang \
+    CXX_i686_unknown_freebsd=i686-unknown-freebsd12-clang++ \
     CC_aarch64_unknown_uefi=clang-11 \
     CXX_aarch64_unknown_uefi=clang++-11 \
     CC_i686_unknown_uefi=clang-11 \
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
index fd0f5da8c49..f42e6f770eb 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
@@ -29,9 +29,9 @@ COPY scripts/cmake.sh /scripts/
 RUN /scripts/cmake.sh
 
 ENV \
-    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-ar \
-    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang \
-    CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang++
+    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-ar \
+    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang \
+    CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang++
 
 ENV HOSTS=x86_64-unknown-freebsd
 
diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh
index b927658b4fd..0d02636db91 100755
--- a/src/ci/docker/scripts/freebsd-toolchain.sh
+++ b/src/ci/docker/scripts/freebsd-toolchain.sh
@@ -5,8 +5,8 @@ set -eux
 
 arch=$1
 binutils_version=2.40
-freebsd_version=13.4
-triple=$arch-unknown-freebsd13
+freebsd_version=12.3
+triple=$arch-unknown-freebsd12
 sysroot=/usr/local/$triple
 
 hide_output() {
@@ -59,7 +59,7 @@ done
 
 # Originally downloaded from:
 # URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz
-URL=https://ci-mirrors.rust-lang.org/rustc/2024-09-13-freebsd-${freebsd_version}-${freebsd_arch}-base.txz
+URL=https://ci-mirrors.rust-lang.org/rustc/2022-05-06-freebsd-${freebsd_version}-${freebsd_arch}-base.txz
 curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}"
 
 # Clang can do cross-builds out of the box, if we give it the right
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 13fbfb51a9e..341d82599fd 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -50,7 +50,7 @@ runners:
   - &job-aarch64-linux
     # Free some disk space to avoid running out of space during the build.
     free_disk: true
-    os: ubuntu-24.04-arm
+    os: ubuntu-22.04-arm
 
   - &job-aarch64-linux-8c
     os: ubuntu-22.04-arm64-8core-32gb
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 3b6abdd8483..e1e17c5917e 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -312,7 +312,7 @@ target | std | host | notes
 [`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ |  | 32-bit x86 (original Pentium) [^x86_32-floats-x87]
 [`i686-apple-darwin`](platform-support/apple-darwin.md) | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+, Penryn) [^x86_32-floats-return-ABI]
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku (Pentium 4) [^x86_32-floats-return-ABI]
-[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd (PentiumPro) [^x86_32-floats-x87]
+[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd (Pentium 4) [^x86_32-floats-x87]
 [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 (Pentium 4) [^x86_32-floats-return-ABI]
 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD (Pentium 4) [^x86_32-floats-return-ABI]
 [`i686-unknown-redox`](platform-support/redox.md) | ✓ |  | i686 Redox OS (PentiumPro) [^x86_32-floats-x87]
diff --git a/src/doc/unstable-book/src/language-features/trait-upcasting.md b/src/doc/unstable-book/src/language-features/trait-upcasting.md
deleted file mode 100644
index a5f99cc86f2..00000000000
--- a/src/doc/unstable-book/src/language-features/trait-upcasting.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# `trait_upcasting`
-
-The tracking issue for this feature is: [#65991]
-
-[#65991]: https://github.com/rust-lang/rust/issues/65991
-
-------------------------
-
-The `trait_upcasting` feature adds support for trait upcasting coercion. This allows a
-trait object of type `dyn Bar` to be cast to a trait object of type `dyn Foo`
-so long as `Bar: Foo`.
-
-```rust,edition2018
-#![feature(trait_upcasting)]
-
-trait Foo {}
-
-trait Bar: Foo {}
-
-impl Foo for i32 {}
-
-impl<T: Foo + ?Sized> Bar for T {}
-
-let bar: &dyn Bar = &123;
-let foo: &dyn Foo = bar;
-```
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 0e3d73849ab8cbbab3ec5c65cbd555586cb2133
+Subproject 2928e32734b04925ee51e1ae88bea9a83d2fd45
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 9fbeab5bf2e..5c5978b5559 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -144,8 +144,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::doc::DOC_NESTED_REFDEFS_INFO,
     crate::doc::DOC_OVERINDENTED_LIST_ITEMS_INFO,
     crate::doc::EMPTY_DOCS_INFO,
-    crate::doc::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
-    crate::doc::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
     crate::doc::MISSING_ERRORS_DOC_INFO,
     crate::doc::MISSING_PANICS_DOC_INFO,
     crate::doc::MISSING_SAFETY_DOC_INFO,
@@ -162,6 +160,8 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO,
     crate::empty_drop::EMPTY_DROP_INFO,
     crate::empty_enum::EMPTY_ENUM_INFO,
+    crate::empty_line_after::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
+    crate::empty_line_after::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
     crate::empty_with_brackets::EMPTY_ENUM_VARIANTS_WITH_BRACKETS_INFO,
     crate::empty_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO,
     crate::endian_bytes::BIG_ENDIAN_BYTES_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/doc/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/doc/empty_line_after.rs
deleted file mode 100644
index 6e85c6af642..00000000000
--- a/src/tools/clippy/clippy_lints/src/doc/empty_line_after.rs
+++ /dev/null
@@ -1,345 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::{SpanRangeExt, snippet_indent};
-use clippy_utils::tokenize_with_text;
-use itertools::Itertools;
-use rustc_ast::AttrStyle;
-use rustc_ast::token::CommentKind;
-use rustc_errors::{Applicability, Diag, SuggestionStyle};
-use rustc_hir::{AttrKind, Attribute, ItemKind, Node};
-use rustc_lexer::TokenKind;
-use rustc_lint::LateContext;
-use rustc_span::{BytePos, ExpnKind, InnerSpan, Span, SpanData};
-
-use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR};
-
-#[derive(Debug, PartialEq, Clone, Copy)]
-enum StopKind {
-    Attr,
-    Doc(CommentKind),
-}
-
-impl StopKind {
-    fn is_doc(self) -> bool {
-        matches!(self, StopKind::Doc(_))
-    }
-}
-
-#[derive(Debug)]
-struct Stop {
-    span: Span,
-    kind: StopKind,
-    first: usize,
-    last: usize,
-}
-
-impl Stop {
-    fn convert_to_inner(&self) -> (Span, String) {
-        let inner = match self.kind {
-            // #|[...]
-            StopKind::Attr => InnerSpan::new(1, 1),
-            // /// or /**
-            //   ^      ^
-            StopKind::Doc(_) => InnerSpan::new(2, 3),
-        };
-        (self.span.from_inner(inner), "!".into())
-    }
-
-    fn comment_out(&self, cx: &LateContext<'_>, suggestions: &mut Vec<(Span, String)>) {
-        match self.kind {
-            StopKind::Attr => {
-                if cx.tcx.sess.source_map().is_multiline(self.span) {
-                    suggestions.extend([
-                        (self.span.shrink_to_lo(), "/* ".into()),
-                        (self.span.shrink_to_hi(), " */".into()),
-                    ]);
-                } else {
-                    suggestions.push((self.span.shrink_to_lo(), "// ".into()));
-                }
-            },
-            StopKind::Doc(CommentKind::Line) => suggestions.push((self.span.shrink_to_lo(), "// ".into())),
-            StopKind::Doc(CommentKind::Block) => {
-                // /** outer */  /*! inner */
-                //  ^             ^
-                let asterisk = self.span.from_inner(InnerSpan::new(1, 2));
-                suggestions.push((asterisk, String::new()));
-            },
-        }
-    }
-
-    fn from_attr(cx: &LateContext<'_>, attr: &Attribute) -> Option<Self> {
-        let SpanData { lo, hi, .. } = attr.span.data();
-        let file = cx.tcx.sess.source_map().lookup_source_file(lo);
-
-        Some(Self {
-            span: attr.span,
-            kind: match attr.kind {
-                AttrKind::Normal(_) => StopKind::Attr,
-                AttrKind::DocComment(comment_kind, _) => StopKind::Doc(comment_kind),
-            },
-            first: file.lookup_line(file.relative_position(lo))?,
-            last: file.lookup_line(file.relative_position(hi))?,
-        })
-    }
-}
-
-/// Represents a set of attrs/doc comments separated by 1 or more empty lines
-///
-/// ```ignore
-/// /// chunk 1 docs
-/// // not an empty line so also part of chunk 1
-/// #[chunk_1_attrs] // <-- prev_stop
-///
-/// /* gap */
-///
-/// /// chunk 2 docs // <-- next_stop
-/// #[chunk_2_attrs]
-/// ```
-struct Gap<'a> {
-    /// The span of individual empty lines including the newline at the end of the line
-    empty_lines: Vec<Span>,
-    has_comment: bool,
-    next_stop: &'a Stop,
-    prev_stop: &'a Stop,
-    /// The chunk that includes [`prev_stop`](Self::prev_stop)
-    prev_chunk: &'a [Stop],
-}
-
-impl<'a> Gap<'a> {
-    fn new(cx: &LateContext<'_>, prev_chunk: &'a [Stop], next_chunk: &'a [Stop]) -> Option<Self> {
-        let prev_stop = prev_chunk.last()?;
-        let next_stop = next_chunk.first()?;
-        let gap_span = prev_stop.span.between(next_stop.span);
-        let gap_snippet = gap_span.get_source_text(cx)?;
-
-        let mut has_comment = false;
-        let mut empty_lines = Vec::new();
-
-        for (token, source, inner_span) in tokenize_with_text(&gap_snippet) {
-            match token {
-                TokenKind::BlockComment {
-                    doc_style: None,
-                    terminated: true,
-                }
-                | TokenKind::LineComment { doc_style: None } => has_comment = true,
-                TokenKind::Whitespace => {
-                    let newlines = source.bytes().positions(|b| b == b'\n');
-                    empty_lines.extend(
-                        newlines
-                            .tuple_windows()
-                            .map(|(a, b)| InnerSpan::new(inner_span.start + a + 1, inner_span.start + b))
-                            .map(|inner_span| gap_span.from_inner(inner_span)),
-                    );
-                },
-                // Ignore cfg_attr'd out attributes as they may contain empty lines, could also be from macro
-                // shenanigans
-                _ => return None,
-            }
-        }
-
-        (!empty_lines.is_empty()).then_some(Self {
-            empty_lines,
-            has_comment,
-            next_stop,
-            prev_stop,
-            prev_chunk,
-        })
-    }
-
-    fn contiguous_empty_lines(&self) -> impl Iterator<Item = Span> + '_ {
-        self.empty_lines
-            // The `+ BytePos(1)` means "next line", because each empty line span is "N:1-N:1".
-            .chunk_by(|a, b| a.hi() + BytePos(1) == b.lo())
-            .map(|chunk| {
-                let first = chunk.first().expect("at least one empty line");
-                let last = chunk.last().expect("at least one empty line");
-                // The BytePos subtraction here is safe, as before an empty line, there must be at least one
-                // attribute/comment. The span needs to start at the end of the previous line.
-                first.with_lo(first.lo() - BytePos(1)).with_hi(last.hi())
-            })
-    }
-}
-
-/// If the node the attributes/docs apply to is the first in the module/crate suggest converting
-/// them to inner attributes/docs
-fn suggest_inner(cx: &LateContext<'_>, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>]) {
-    let Some(owner) = cx.last_node_with_lint_attrs.as_owner() else {
-        return;
-    };
-    let parent_desc = match cx.tcx.parent_hir_node(owner.into()) {
-        Node::Item(item)
-            if let ItemKind::Mod(parent_mod) = item.kind
-                && let [first, ..] = parent_mod.item_ids
-                && first.owner_id == owner =>
-        {
-            "parent module"
-        },
-        Node::Crate(crate_mod)
-            if let Some(first) = crate_mod
-                .item_ids
-                .iter()
-                .map(|&id| cx.tcx.hir().item(id))
-                // skip prelude imports
-                .find(|item| !matches!(item.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
-                && first.owner_id == owner =>
-        {
-            "crate"
-        },
-        _ => return,
-    };
-
-    diag.multipart_suggestion_verbose(
-        match kind {
-            StopKind::Attr => format!("if the attribute should apply to the {parent_desc} use an inner attribute"),
-            StopKind::Doc(_) => format!("if the comment should document the {parent_desc} use an inner doc comment"),
-        },
-        gaps.iter()
-            .flat_map(|gap| gap.prev_chunk)
-            .map(Stop::convert_to_inner)
-            .collect(),
-        Applicability::MaybeIncorrect,
-    );
-}
-
-fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool {
-    let Some(first_gap) = gaps.first() else {
-        return false;
-    };
-    let empty_lines = || gaps.iter().flat_map(|gap| gap.empty_lines.iter().copied());
-    let contiguous_empty_lines = || gaps.iter().flat_map(Gap::contiguous_empty_lines);
-    let mut has_comment = false;
-    let mut has_attr = false;
-    for gap in gaps {
-        has_comment |= gap.has_comment;
-        if !has_attr {
-            has_attr = gap.prev_chunk.iter().any(|stop| stop.kind == StopKind::Attr);
-        }
-    }
-    let kind = first_gap.prev_stop.kind;
-    let (lint, kind_desc) = match kind {
-        StopKind::Attr => (EMPTY_LINE_AFTER_OUTER_ATTR, "outer attribute"),
-        StopKind::Doc(_) => (EMPTY_LINE_AFTER_DOC_COMMENTS, "doc comment"),
-    };
-    let (lines, are, them) = if empty_lines().nth(1).is_some() {
-        ("lines", "are", "them")
-    } else {
-        ("line", "is", "it")
-    };
-    span_lint_and_then(
-        cx,
-        lint,
-        first_gap.prev_stop.span.to(empty_lines().last().unwrap()),
-        format!("empty {lines} after {kind_desc}"),
-        |diag| {
-            if let Some(owner) = cx.last_node_with_lint_attrs.as_owner() {
-                let def_id = owner.to_def_id();
-                let def_descr = cx.tcx.def_descr(def_id);
-                diag.span_label(
-                    cx.tcx.def_span(def_id),
-                    match kind {
-                        StopKind::Attr => format!("the attribute applies to this {def_descr}"),
-                        StopKind::Doc(_) => format!("the comment documents this {def_descr}"),
-                    },
-                );
-            }
-
-            diag.multipart_suggestion_with_style(
-                format!("if the empty {lines} {are} unintentional remove {them}"),
-                contiguous_empty_lines()
-                    .map(|empty_lines| (empty_lines, String::new()))
-                    .collect(),
-                Applicability::MaybeIncorrect,
-                SuggestionStyle::HideCodeAlways,
-            );
-
-            if has_comment && kind.is_doc() {
-                // Likely doc comments that applied to some now commented out code
-                //
-                // /// Old docs for Foo
-                // // struct Foo;
-
-                let mut suggestions = Vec::new();
-                for stop in gaps.iter().flat_map(|gap| gap.prev_chunk) {
-                    stop.comment_out(cx, &mut suggestions);
-                }
-                let name = match cx.tcx.hir().opt_name(cx.last_node_with_lint_attrs) {
-                    Some(name) => format!("`{name}`"),
-                    None => "this".into(),
-                };
-                diag.multipart_suggestion_verbose(
-                    format!("if the doc comment should not document {name} comment it out"),
-                    suggestions,
-                    Applicability::MaybeIncorrect,
-                );
-            } else {
-                suggest_inner(cx, diag, kind, gaps);
-            }
-
-            if kind == StopKind::Doc(CommentKind::Line)
-                && gaps
-                    .iter()
-                    .all(|gap| !gap.has_comment && gap.next_stop.kind == StopKind::Doc(CommentKind::Line))
-            {
-                // Commentless empty gaps between line doc comments, possibly intended to be part of the markdown
-
-                let indent = snippet_indent(cx, first_gap.prev_stop.span).unwrap_or_default();
-                diag.multipart_suggestion_verbose(
-                    format!("if the documentation should include the empty {lines} include {them} in the comment"),
-                    empty_lines()
-                        .map(|empty_line| (empty_line, format!("{indent}///")))
-                        .collect(),
-                    Applicability::MaybeIncorrect,
-                );
-            }
-        },
-    );
-    kind.is_doc()
-}
-
-/// Returns `true` if [`EMPTY_LINE_AFTER_DOC_COMMENTS`] triggered, used to skip other doc comment
-/// lints where they would be confusing
-///
-/// [`EMPTY_LINE_AFTER_OUTER_ATTR`] is also here to share an implementation but does not return
-/// `true` if it triggers
-pub(super) fn check(cx: &LateContext<'_>, attrs: &[Attribute]) -> bool {
-    let mut outer = attrs
-        .iter()
-        .filter(|attr| attr.style == AttrStyle::Outer && !attr.span.from_expansion())
-        .map(|attr| Stop::from_attr(cx, attr))
-        .collect::<Option<Vec<_>>>()
-        .unwrap_or_default();
-
-    if outer.is_empty() {
-        return false;
-    }
-
-    // Push a fake attribute Stop for the item itself so we check for gaps between the last outer
-    // attr/doc comment and the item they apply to
-    let span = cx.tcx.hir().span(cx.last_node_with_lint_attrs);
-    if !span.from_expansion()
-        && let Ok(line) = cx.tcx.sess.source_map().lookup_line(span.lo())
-    {
-        outer.push(Stop {
-            span,
-            kind: StopKind::Attr,
-            first: line.line,
-            // last doesn't need to be accurate here, we don't compare it with anything
-            last: line.line,
-        });
-    }
-
-    let mut gaps = Vec::new();
-    let mut last = 0;
-    for pos in outer
-        .array_windows()
-        .positions(|[a, b]| b.first.saturating_sub(a.last) > 1)
-    {
-        // we want to be after the first stop in the window
-        let pos = pos + 1;
-        if let Some(gap) = Gap::new(cx, &outer[last..pos], &outer[pos..]) {
-            last = pos;
-            gaps.push(gap);
-        }
-    }
-
-    check_gaps(cx, &gaps)
-}
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 3d8ce7becdb..42e1f7fd950 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -33,7 +33,6 @@ use rustc_span::{Span, sym};
 use std::ops::Range;
 use url::Url;
 
-mod empty_line_after;
 mod include_in_doc_without_cfg;
 mod link_with_quotes;
 mod markdown;
@@ -493,82 +492,6 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for empty lines after outer attributes
-    ///
-    /// ### Why is this bad?
-    /// The attribute may have meant to be an inner attribute (`#![attr]`). If
-    /// it was meant to be an outer attribute (`#[attr]`) then the empty line
-    /// should be removed
-    ///
-    /// ### Example
-    /// ```no_run
-    /// #[allow(dead_code)]
-    ///
-    /// fn not_quite_good_code() {}
-    /// ```
-    ///
-    /// Use instead:
-    /// ```no_run
-    /// // Good (as inner attribute)
-    /// #![allow(dead_code)]
-    ///
-    /// fn this_is_fine() {}
-    ///
-    /// // or
-    ///
-    /// // Good (as outer attribute)
-    /// #[allow(dead_code)]
-    /// fn this_is_fine_too() {}
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub EMPTY_LINE_AFTER_OUTER_ATTR,
-    suspicious,
-    "empty line after outer attribute"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for empty lines after doc comments.
-    ///
-    /// ### Why is this bad?
-    /// The doc comment may have meant to be an inner doc comment, regular
-    /// comment or applied to some old code that is now commented out. If it was
-    /// intended to be a doc comment, then the empty line should be removed.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// /// Some doc comment with a blank line after it.
-    ///
-    /// fn f() {}
-    ///
-    /// /// Docs for `old_code`
-    /// // fn old_code() {}
-    ///
-    /// fn new_code() {}
-    /// ```
-    ///
-    /// Use instead:
-    /// ```no_run
-    /// //! Convert it to an inner doc comment
-    ///
-    /// // Or a regular comment
-    ///
-    /// /// Or remove the empty line
-    /// fn f() {}
-    ///
-    /// // /// Docs for `old_code`
-    /// // fn old_code() {}
-    ///
-    /// fn new_code() {}
-    /// ```
-    #[clippy::version = "1.70.0"]
-    pub EMPTY_LINE_AFTER_DOC_COMMENTS,
-    suspicious,
-    "empty line after doc comments"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
     /// Checks if included files in doc comments are included only for `cfg(doc)`.
     ///
     /// ### Why restrict this?
@@ -650,8 +573,6 @@ impl_lint_pass!(Documentation => [
     EMPTY_DOCS,
     DOC_LAZY_CONTINUATION,
     DOC_OVERINDENTED_LIST_ITEMS,
-    EMPTY_LINE_AFTER_OUTER_ATTR,
-    EMPTY_LINE_AFTER_DOC_COMMENTS,
     TOO_LONG_FIRST_DOC_PARAGRAPH,
     DOC_INCLUDE_WITHOUT_CFG,
 ]);
@@ -784,7 +705,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
     }
 
     include_in_doc_without_cfg::check(cx, attrs);
-    if suspicious_doc_comments::check(cx, attrs) || empty_line_after::check(cx, attrs) || is_doc_hidden(attrs) {
+    if suspicious_doc_comments::check(cx, attrs) || is_doc_hidden(attrs) {
         return None;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/empty_line_after.rs
new file mode 100644
index 00000000000..578ff6e38a6
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/empty_line_after.rs
@@ -0,0 +1,492 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::{SpanRangeExt, snippet_indent};
+use clippy_utils::tokenize_with_text;
+use itertools::Itertools;
+use rustc_ast::token::CommentKind;
+use rustc_ast::{AssocItemKind, AttrKind, AttrStyle, Attribute, Crate, Item, ItemKind, ModKind, NodeId};
+use rustc_errors::{Applicability, Diag, SuggestionStyle};
+use rustc_lexer::TokenKind;
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_session::impl_lint_pass;
+use rustc_span::symbol::kw;
+use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for empty lines after outer attributes
+    ///
+    /// ### Why is this bad?
+    /// The attribute may have meant to be an inner attribute (`#![attr]`). If
+    /// it was meant to be an outer attribute (`#[attr]`) then the empty line
+    /// should be removed
+    ///
+    /// ### Example
+    /// ```no_run
+    /// #[allow(dead_code)]
+    ///
+    /// fn not_quite_good_code() {}
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// // Good (as inner attribute)
+    /// #![allow(dead_code)]
+    ///
+    /// fn this_is_fine() {}
+    ///
+    /// // or
+    ///
+    /// // Good (as outer attribute)
+    /// #[allow(dead_code)]
+    /// fn this_is_fine_too() {}
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub EMPTY_LINE_AFTER_OUTER_ATTR,
+    suspicious,
+    "empty line after outer attribute"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for empty lines after doc comments.
+    ///
+    /// ### Why is this bad?
+    /// The doc comment may have meant to be an inner doc comment, regular
+    /// comment or applied to some old code that is now commented out. If it was
+    /// intended to be a doc comment, then the empty line should be removed.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// /// Some doc comment with a blank line after it.
+    ///
+    /// fn f() {}
+    ///
+    /// /// Docs for `old_code`
+    /// // fn old_code() {}
+    ///
+    /// fn new_code() {}
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// //! Convert it to an inner doc comment
+    ///
+    /// // Or a regular comment
+    ///
+    /// /// Or remove the empty line
+    /// fn f() {}
+    ///
+    /// // /// Docs for `old_code`
+    /// // fn old_code() {}
+    ///
+    /// fn new_code() {}
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub EMPTY_LINE_AFTER_DOC_COMMENTS,
+    suspicious,
+    "empty line after doc comments"
+}
+
+#[derive(Debug)]
+struct ItemInfo {
+    kind: &'static str,
+    name: Symbol,
+    span: Span,
+    mod_items: Option<NodeId>,
+}
+
+pub struct EmptyLineAfter {
+    items: Vec<ItemInfo>,
+}
+
+impl_lint_pass!(EmptyLineAfter => [
+    EMPTY_LINE_AFTER_OUTER_ATTR,
+    EMPTY_LINE_AFTER_DOC_COMMENTS,
+]);
+
+impl EmptyLineAfter {
+    pub fn new() -> Self {
+        Self { items: Vec::new() }
+    }
+}
+
+#[derive(Debug, PartialEq, Clone, Copy)]
+enum StopKind {
+    Attr,
+    Doc(CommentKind),
+}
+
+impl StopKind {
+    fn is_doc(self) -> bool {
+        matches!(self, StopKind::Doc(_))
+    }
+}
+
+#[derive(Debug)]
+struct Stop {
+    span: Span,
+    kind: StopKind,
+    first: usize,
+    last: usize,
+}
+
+impl Stop {
+    fn convert_to_inner(&self) -> (Span, String) {
+        let inner = match self.kind {
+            // #![...]
+            StopKind::Attr => InnerSpan::new(1, 1),
+            // /// or /**
+            //   ^      ^
+            StopKind::Doc(_) => InnerSpan::new(2, 3),
+        };
+        (self.span.from_inner(inner), "!".into())
+    }
+
+    fn comment_out(&self, cx: &EarlyContext<'_>, suggestions: &mut Vec<(Span, String)>) {
+        match self.kind {
+            StopKind::Attr => {
+                if cx.sess().source_map().is_multiline(self.span) {
+                    suggestions.extend([
+                        (self.span.shrink_to_lo(), "/* ".into()),
+                        (self.span.shrink_to_hi(), " */".into()),
+                    ]);
+                } else {
+                    suggestions.push((self.span.shrink_to_lo(), "// ".into()));
+                }
+            },
+            StopKind::Doc(CommentKind::Line) => suggestions.push((self.span.shrink_to_lo(), "// ".into())),
+            StopKind::Doc(CommentKind::Block) => {
+                // /** outer */  /*! inner */
+                //  ^             ^
+                let asterisk = self.span.from_inner(InnerSpan::new(1, 2));
+                suggestions.push((asterisk, String::new()));
+            },
+        }
+    }
+
+    fn from_attr(cx: &EarlyContext<'_>, attr: &Attribute) -> Option<Self> {
+        let SpanData { lo, hi, .. } = attr.span.data();
+        let file = cx.sess().source_map().lookup_source_file(lo);
+
+        Some(Self {
+            span: attr.span,
+            kind: match attr.kind {
+                AttrKind::Normal(_) => StopKind::Attr,
+                AttrKind::DocComment(comment_kind, _) => StopKind::Doc(comment_kind),
+            },
+            first: file.lookup_line(file.relative_position(lo))?,
+            last: file.lookup_line(file.relative_position(hi))?,
+        })
+    }
+}
+
+/// Represents a set of attrs/doc comments separated by 1 or more empty lines
+///
+/// ```ignore
+/// /// chunk 1 docs
+/// // not an empty line so also part of chunk 1
+/// #[chunk_1_attrs] // <-- prev_stop
+///
+/// /* gap */
+///
+/// /// chunk 2 docs // <-- next_stop
+/// #[chunk_2_attrs]
+/// ```
+struct Gap<'a> {
+    /// The span of individual empty lines including the newline at the end of the line
+    empty_lines: Vec<Span>,
+    has_comment: bool,
+    next_stop: &'a Stop,
+    prev_stop: &'a Stop,
+    /// The chunk that includes [`prev_stop`](Self::prev_stop)
+    prev_chunk: &'a [Stop],
+}
+
+impl<'a> Gap<'a> {
+    fn new(cx: &EarlyContext<'_>, prev_chunk: &'a [Stop], next_chunk: &'a [Stop]) -> Option<Self> {
+        let prev_stop = prev_chunk.last()?;
+        let next_stop = next_chunk.first()?;
+        let gap_span = prev_stop.span.between(next_stop.span);
+        let gap_snippet = gap_span.get_source_text(cx)?;
+
+        let mut has_comment = false;
+        let mut empty_lines = Vec::new();
+
+        for (token, source, inner_span) in tokenize_with_text(&gap_snippet) {
+            match token {
+                TokenKind::BlockComment {
+                    doc_style: None,
+                    terminated: true,
+                }
+                | TokenKind::LineComment { doc_style: None } => has_comment = true,
+                TokenKind::Whitespace => {
+                    let newlines = source.bytes().positions(|b| b == b'\n');
+                    empty_lines.extend(
+                        newlines
+                            .tuple_windows()
+                            .map(|(a, b)| InnerSpan::new(inner_span.start + a + 1, inner_span.start + b))
+                            .map(|inner_span| gap_span.from_inner(inner_span)),
+                    );
+                },
+                // Ignore cfg_attr'd out attributes as they may contain empty lines, could also be from macro
+                // shenanigans
+                _ => return None,
+            }
+        }
+
+        (!empty_lines.is_empty()).then_some(Self {
+            empty_lines,
+            has_comment,
+            next_stop,
+            prev_stop,
+            prev_chunk,
+        })
+    }
+
+    fn contiguous_empty_lines(&self) -> impl Iterator<Item = Span> + '_ {
+        self.empty_lines
+            // The `+ BytePos(1)` means "next line", because each empty line span is "N:1-N:1".
+            .chunk_by(|a, b| a.hi() + BytePos(1) == b.lo())
+            .map(|chunk| {
+                let first = chunk.first().expect("at least one empty line");
+                let last = chunk.last().expect("at least one empty line");
+                // The BytePos subtraction here is safe, as before an empty line, there must be at least one
+                // attribute/comment. The span needs to start at the end of the previous line.
+                first.with_lo(first.lo() - BytePos(1)).with_hi(last.hi())
+            })
+    }
+}
+
+impl EmptyLineAfter {
+    fn check_gaps(&self, cx: &EarlyContext<'_>, gaps: &[Gap<'_>], id: NodeId) {
+        let Some(first_gap) = gaps.first() else {
+            return;
+        };
+        let empty_lines = || gaps.iter().flat_map(|gap| gap.empty_lines.iter().copied());
+        let contiguous_empty_lines = || gaps.iter().flat_map(Gap::contiguous_empty_lines);
+        let mut has_comment = false;
+        let mut has_attr = false;
+        for gap in gaps {
+            has_comment |= gap.has_comment;
+            if !has_attr {
+                has_attr = gap.prev_chunk.iter().any(|stop| stop.kind == StopKind::Attr);
+            }
+        }
+        let kind = first_gap.prev_stop.kind;
+        let (lint, kind_desc) = match kind {
+            StopKind::Attr => (EMPTY_LINE_AFTER_OUTER_ATTR, "outer attribute"),
+            StopKind::Doc(_) => (EMPTY_LINE_AFTER_DOC_COMMENTS, "doc comment"),
+        };
+        let (lines, are, them) = if empty_lines().nth(1).is_some() {
+            ("lines", "are", "them")
+        } else {
+            ("line", "is", "it")
+        };
+        span_lint_and_then(
+            cx,
+            lint,
+            first_gap.prev_stop.span.to(empty_lines().last().unwrap()),
+            format!("empty {lines} after {kind_desc}"),
+            |diag| {
+                let info = self.items.last().unwrap();
+                diag.span_label(info.span, match kind {
+                    StopKind::Attr => format!("the attribute applies to this {}", info.kind),
+                    StopKind::Doc(_) => format!("the comment documents this {}", info.kind),
+                });
+
+                diag.multipart_suggestion_with_style(
+                    format!("if the empty {lines} {are} unintentional, remove {them}"),
+                    contiguous_empty_lines()
+                        .map(|empty_lines| (empty_lines, String::new()))
+                        .collect(),
+                    Applicability::MaybeIncorrect,
+                    SuggestionStyle::HideCodeAlways,
+                );
+
+                if has_comment && kind.is_doc() {
+                    // Likely doc comments that applied to some now commented out code
+                    //
+                    // /// Old docs for Foo
+                    // // struct Foo;
+
+                    let mut suggestions = Vec::new();
+                    for stop in gaps.iter().flat_map(|gap| gap.prev_chunk) {
+                        stop.comment_out(cx, &mut suggestions);
+                    }
+                    diag.multipart_suggestion_verbose(
+                        format!("if the doc comment should not document `{}` comment it out", info.name),
+                        suggestions,
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    self.suggest_inner(diag, kind, gaps, id);
+                }
+
+                if kind == StopKind::Doc(CommentKind::Line)
+                    && gaps
+                        .iter()
+                        .all(|gap| !gap.has_comment && gap.next_stop.kind == StopKind::Doc(CommentKind::Line))
+                {
+                    // Commentless empty gaps between line doc comments, possibly intended to be part of the markdown
+
+                    let indent = snippet_indent(cx, first_gap.prev_stop.span).unwrap_or_default();
+                    diag.multipart_suggestion_verbose(
+                        format!("if the documentation should include the empty {lines} include {them} in the comment"),
+                        empty_lines()
+                            .map(|empty_line| (empty_line, format!("{indent}///")))
+                            .collect(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            },
+        );
+    }
+
+    /// If the node the attributes/docs apply to is the first in the module/crate suggest converting
+    /// them to inner attributes/docs
+    fn suggest_inner(&self, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>], id: NodeId) {
+        if let Some(parent) = self.items.iter().rev().nth(1)
+            && (parent.kind == "module" || parent.kind == "crate")
+            && parent.mod_items == Some(id)
+        {
+            let desc = if parent.kind == "module" {
+                "parent module"
+            } else {
+                parent.kind
+            };
+            diag.multipart_suggestion_verbose(
+                match kind {
+                    StopKind::Attr => format!("if the attribute should apply to the {desc} use an inner attribute"),
+                    StopKind::Doc(_) => format!("if the comment should document the {desc} use an inner doc comment"),
+                },
+                gaps.iter()
+                    .flat_map(|gap| gap.prev_chunk)
+                    .map(Stop::convert_to_inner)
+                    .collect(),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
+    fn check_item_kind(
+        &mut self,
+        cx: &EarlyContext<'_>,
+        kind: &ItemKind,
+        ident: &Ident,
+        span: Span,
+        attrs: &[Attribute],
+        id: NodeId,
+    ) {
+        self.items.push(ItemInfo {
+            kind: kind.descr(),
+            name: ident.name,
+            span: if span.contains(ident.span) {
+                span.with_hi(ident.span.hi())
+            } else {
+                span.with_hi(span.lo())
+            },
+            mod_items: match kind {
+                ItemKind::Mod(_, ModKind::Loaded(items, _, _, _)) => items
+                    .iter()
+                    .filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
+                    .map(|i| i.id)
+                    .next(),
+                _ => None,
+            },
+        });
+
+        let mut outer = attrs
+            .iter()
+            .filter(|attr| attr.style == AttrStyle::Outer && !attr.span.from_expansion())
+            .map(|attr| Stop::from_attr(cx, attr))
+            .collect::<Option<Vec<_>>>()
+            .unwrap_or_default();
+
+        if outer.is_empty() {
+            return;
+        }
+
+        // Push a fake attribute Stop for the item itself so we check for gaps between the last outer
+        // attr/doc comment and the item they apply to
+        let span = self.items.last().unwrap().span;
+        if !span.from_expansion()
+            && let Ok(line) = cx.sess().source_map().lookup_line(span.lo())
+        {
+            outer.push(Stop {
+                span,
+                kind: StopKind::Attr,
+                first: line.line,
+                // last doesn't need to be accurate here, we don't compare it with anything
+                last: line.line,
+            });
+        }
+
+        let mut gaps = Vec::new();
+        let mut last = 0;
+        for pos in outer
+            .array_windows()
+            .positions(|[a, b]| b.first.saturating_sub(a.last) > 1)
+        {
+            // we want to be after the first stop in the window
+            let pos = pos + 1;
+            if let Some(gap) = Gap::new(cx, &outer[last..pos], &outer[pos..]) {
+                last = pos;
+                gaps.push(gap);
+            }
+        }
+
+        self.check_gaps(cx, &gaps, id);
+    }
+}
+
+impl EarlyLintPass for EmptyLineAfter {
+    fn check_crate(&mut self, _: &EarlyContext<'_>, krate: &Crate) {
+        self.items.push(ItemInfo {
+            kind: "crate",
+            name: kw::Crate,
+            span: krate.spans.inner_span.with_hi(krate.spans.inner_span.lo()),
+            mod_items: krate
+                .items
+                .iter()
+                .filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
+                .map(|i| i.id)
+                .next(),
+        });
+    }
+
+    fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &Item) {
+        self.items.pop();
+    }
+    fn check_impl_item_post(&mut self, _: &EarlyContext<'_>, _: &Item<AssocItemKind>) {
+        self.items.pop();
+    }
+    fn check_trait_item_post(&mut self, _: &EarlyContext<'_>, _: &Item<AssocItemKind>) {
+        self.items.pop();
+    }
+
+    fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &Item<AssocItemKind>) {
+        self.check_item_kind(
+            cx,
+            &item.kind.clone().into(),
+            &item.ident,
+            item.span,
+            &item.attrs,
+            item.id,
+        );
+    }
+
+    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &Item<AssocItemKind>) {
+        self.check_item_kind(
+            cx,
+            &item.kind.clone().into(),
+            &item.ident,
+            item.span,
+            &item.attrs,
+            item.id,
+        );
+    }
+
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        self.check_item_kind(cx, &item.kind, &item.ident, item.span, &item.attrs, item.id);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 8887ab7ec0d..13218331a67 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -126,6 +126,7 @@ mod duplicate_mod;
 mod else_if_without_else;
 mod empty_drop;
 mod empty_enum;
+mod empty_line_after;
 mod empty_with_brackets;
 mod endian_bytes;
 mod entry;
@@ -973,6 +974,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf)));
     store.register_late_pass(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp));
     store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
+    store.register_early_pass(|| Box::new(empty_line_after::EmptyLineAfter::new()));
     store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
     store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern));
     store.register_late_pass(|_| Box::<unnecessary_semicolon::UnnecessarySemicolon>::default());
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
index 04446787b6c..a065654e319 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
@@ -66,3 +66,19 @@ fn escape_3() {}
 
 /// Backslashes ` \` within code blocks don't count.
 fn escape_4() {}
+
+trait Foo {
+    fn bar();
+}
+
+struct Bar;
+impl Foo for Bar {
+    // NOTE: false positive
+    /// Returns an `Option<Month>` from a i64, assuming a 1-index, January = 1.
+    ///
+    /// `Month::from_i64(n: i64)`: | `1`                  | `2`                   | ... | `12`
+    /// ---------------------------| -------------------- | --------------------- | ... | -----
+    /// ``:                        | Some(Month::January) | Some(Month::February) | ... |
+    /// Some(Month::December)
+    fn bar() {}
+}
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
index 50324010e97..c9fd25eb1a1 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
@@ -94,5 +94,17 @@ LL | /// Escaped \` ` backticks don't count, but unescaped backticks do.
    |
    = help: a backtick may be missing a pair
 
-error: aborting due to 10 previous errors
+error: backticks are unbalanced
+  --> tests/ui/doc/unbalanced_ticks.rs:79:9
+   |
+LL |       /// `Month::from_i64(n: i64)`: | `1`                  | `2`                   | ... | `12`
+   |  _________^
+LL | |     /// ---------------------------| -------------------- | --------------------- | ... | -----
+LL | |     /// ``:                        | Some(Month::January) | Some(Month::February) | ... |
+LL | |     /// Some(Month::December)
+   | |_____________________________^
+   |
+   = help: a backtick may be missing a pair
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed
index fd6a94b6a80..3772b465fdb 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed
+++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed
@@ -132,4 +132,13 @@ pub struct BlockComment;
 ))]
 fn empty_line_in_cfg_attr() {}
 
+trait Foo {
+    fn bar();
+}
+
+impl Foo for LineComment {
+    /// comment on assoc item
+    fn bar() {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed
index 7a57dcd9233..3028d03b669 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed
+++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed
@@ -141,4 +141,13 @@ pub struct BlockComment;
 ))]
 fn empty_line_in_cfg_attr() {}
 
+trait Foo {
+    fn bar();
+}
+
+impl Foo for LineComment {
+    /// comment on assoc item
+    fn bar() {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs
index 1da761a5c3d..ae4ebc271fa 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs
+++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs
@@ -144,4 +144,14 @@ pub struct BlockComment;
 ))]
 fn empty_line_in_cfg_attr() {}
 
+trait Foo {
+    fn bar();
+}
+
+impl Foo for LineComment {
+    /// comment on assoc item
+
+    fn bar() {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr
index c5d5f3d3759..7b197ae67e0 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr
+++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr
@@ -5,11 +5,11 @@ LL | / /// for the crate
 LL | |
    | |_^
 LL |   fn first_in_crate() {}
-   |   ------------------- the comment documents this function
+   |   ----------------- the comment documents this function
    |
    = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_doc_comments)]`
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the comment should document the crate use an inner doc comment
    |
 LL ~ //! Meant to be an
@@ -24,9 +24,9 @@ LL | /     /// for the module
 LL | |
    | |_^
 LL |       fn first_in_module() {}
-   |       -------------------- the comment documents this function
+   |       ------------------ the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the comment should document the parent module use an inner doc comment
    |
 LL ~     //! Meant to be an
@@ -42,9 +42,9 @@ LL | |
    | |_^
 LL |       /// Blank line
 LL |       fn indented() {}
-   |       ------------- the comment documents this function
+   |       ----------- the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the documentation should include the empty line include it in the comment
    |
 LL |     ///
@@ -57,9 +57,9 @@ LL | / /// This should produce a warning
 LL | |
    | |_^
 LL |   fn with_doc_and_newline() {}
-   |   ------------------------- the comment documents this function
+   |   ----------------------- the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty lines after doc comment
   --> tests/ui/empty_line_after/doc_comments.rs:44:1
@@ -72,9 +72,9 @@ LL | |
    | |_^
 ...
 LL |   fn three_attributes() {}
-   |   --------------------- the comment documents this function
+   |   ------------------- the comment documents this function
    |
-   = help: if the empty lines are unintentional remove them
+   = help: if the empty lines are unintentional, remove them
 
 error: empty line after doc comment
   --> tests/ui/empty_line_after/doc_comments.rs:56:5
@@ -84,9 +84,9 @@ LL | |     // fn old_code() {}
 LL | |
    | |_^
 LL |       fn new_code() {}
-   |       ------------- the comment documents this function
+   |       ----------- the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the doc comment should not document `new_code` comment it out
    |
 LL |     // /// docs for `old_code`
@@ -106,7 +106,7 @@ LL | |
 LL |       struct Multiple;
    |       --------------- the comment documents this struct
    |
-   = help: if the empty lines are unintentional remove them
+   = help: if the empty lines are unintentional, remove them
 help: if the doc comment should not document `Multiple` comment it out
    |
 LL ~     // /// Docs
@@ -126,9 +126,9 @@ LL | |      */
 LL | |
    | |_^
 LL |       fn first_in_module() {}
-   |       -------------------- the comment documents this function
+   |       ------------------ the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the comment should document the parent module use an inner doc comment
    |
 LL |     /*!
@@ -145,9 +145,9 @@ LL | |
    | |_^
 ...
 LL |       fn new_code() {}
-   |       ------------- the comment documents this function
+   |       ----------- the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the doc comment should not document `new_code` comment it out
    |
 LL -     /**
@@ -163,13 +163,24 @@ LL | |
    | |_^
 LL |       /// Docs for `new_code2`
 LL |       fn new_code2() {}
-   |       -------------- the comment documents this function
+   |       ------------ the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the doc comment should not document `new_code2` comment it out
    |
 LL |     // /// Docs for `old_code2`
    |     ++
 
-error: aborting due to 10 previous errors
+error: empty line after doc comment
+  --> tests/ui/empty_line_after/doc_comments.rs:152:5
+   |
+LL | /     /// comment on assoc item
+LL | |
+   | |_^
+LL |       fn bar() {}
+   |       ------ the comment documents this function
+   |
+   = help: if the empty line is unintentional, remove it
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
index a95306e2fa3..519ba6e6761 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
+++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
@@ -5,11 +5,11 @@ LL | / #[crate_type = "lib"]
 LL | |
    | |_^
 LL |   fn first_in_crate() {}
-   |   ------------------- the attribute applies to this function
+   |   ----------------- the attribute applies to this function
    |
    = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]`
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the attribute should apply to the crate use an inner attribute
    |
 LL | #![crate_type = "lib"]
@@ -23,9 +23,9 @@ LL | |
    | |_^
 LL |   /// some comment
 LL |   fn with_one_newline_and_comment() {}
-   |   --------------------------------- the attribute applies to this function
+   |   ------------------------------- the attribute applies to this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty line after outer attribute
   --> tests/ui/empty_line_after/outer_attribute.rs:23:1
@@ -34,9 +34,9 @@ LL | / #[inline]
 LL | |
    | |_^
 LL |   fn with_one_newline() {}
-   |   --------------------- the attribute applies to this function
+   |   ------------------- the attribute applies to this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty lines after outer attribute
   --> tests/ui/empty_line_after/outer_attribute.rs:30:5
@@ -46,9 +46,9 @@ LL | |
 LL | |
    | |_^
 LL |       fn with_two_newlines() {}
-   |       ---------------------- the attribute applies to this function
+   |       -------------------- the attribute applies to this function
    |
-   = help: if the empty lines are unintentional remove them
+   = help: if the empty lines are unintentional, remove them
 help: if the attribute should apply to the parent module use an inner attribute
    |
 LL |     #![crate_type = "lib"]
@@ -63,7 +63,7 @@ LL | |
 LL |   enum Baz {
    |   -------- the attribute applies to this enum
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty line after outer attribute
   --> tests/ui/empty_line_after/outer_attribute.rs:45:1
@@ -74,7 +74,7 @@ LL | |
 LL |   struct Foo {
    |   ---------- the attribute applies to this struct
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty line after outer attribute
   --> tests/ui/empty_line_after/outer_attribute.rs:53:1
@@ -85,7 +85,7 @@ LL | |
 LL |   mod foo {}
    |   ------- the attribute applies to this module
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty line after outer attribute
   --> tests/ui/empty_line_after/outer_attribute.rs:58:1
@@ -95,9 +95,9 @@ LL | | // Still lint cases where the empty line does not immediately follow the
 LL | |
    | |_^
 LL |   fn comment_before_empty_line() {}
-   |   ------------------------------ the attribute applies to this function
+   |   ---------------------------- the attribute applies to this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty lines after outer attribute
   --> tests/ui/empty_line_after/outer_attribute.rs:64:1
@@ -107,9 +107,9 @@ LL | / #[allow(unused)]
 LL | |
    | |_^
 LL |   pub fn isolated_comment() {}
-   |   ------------------------- the attribute applies to this function
+   |   ----------------------- the attribute applies to this function
    |
-   = help: if the empty lines are unintentional remove them
+   = help: if the empty lines are unintentional, remove them
 
 error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed b/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed
index 614fc03571e..d3df6a41cb1 100644
--- a/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed
+++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed
@@ -1,5 +1,6 @@
 #![allow(unused)]
 #![warn(clippy::suspicious_doc_comments)]
+#![allow(clippy::empty_line_after_doc_comments)]
 
 //! Real module documentation.
 //! Fake module documentation.
diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.rs b/src/tools/clippy/tests/ui/suspicious_doc_comments.rs
index 7dcba0fefc9..04db2b199c0 100644
--- a/src/tools/clippy/tests/ui/suspicious_doc_comments.rs
+++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.rs
@@ -1,5 +1,6 @@
 #![allow(unused)]
 #![warn(clippy::suspicious_doc_comments)]
+#![allow(clippy::empty_line_after_doc_comments)]
 
 //! Real module documentation.
 ///! Fake module documentation.
diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr b/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr
index f12053b1595..c34e39cd0fc 100644
--- a/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr
@@ -1,5 +1,5 @@
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:5:1
+  --> tests/ui/suspicious_doc_comments.rs:6:1
    |
 LL | ///! Fake module documentation.
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL | //! Fake module documentation.
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:9:5
+  --> tests/ui/suspicious_doc_comments.rs:10:5
    |
 LL |     ///! This module contains useful functions.
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL |     //! This module contains useful functions.
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:21:5
+  --> tests/ui/suspicious_doc_comments.rs:22:5
    |
 LL | /     /**! This module contains useful functions.
 LL | |      */
@@ -36,7 +36,7 @@ LL +      */
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:35:5
+  --> tests/ui/suspicious_doc_comments.rs:36:5
    |
 LL | /     ///! This module
 LL | |     ///! contains
@@ -51,7 +51,7 @@ LL ~     //! useful functions.
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:43:5
+  --> tests/ui/suspicious_doc_comments.rs:44:5
    |
 LL | /     ///! a
 LL | |     ///! b
@@ -64,7 +64,7 @@ LL ~     //! b
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:51:5
+  --> tests/ui/suspicious_doc_comments.rs:52:5
    |
 LL |     ///! a
    |     ^^^^^^
@@ -75,7 +75,7 @@ LL |     //! a
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:57:5
+  --> tests/ui/suspicious_doc_comments.rs:58:5
    |
 LL | /     ///! a
 LL | |
@@ -90,7 +90,7 @@ LL ~     //! b
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:69:5
+  --> tests/ui/suspicious_doc_comments.rs:70:5
    |
 LL |     ///! Very cool macro
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -101,7 +101,7 @@ LL |     //! Very cool macro
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:76:5
+  --> tests/ui/suspicious_doc_comments.rs:77:5
    |
 LL |     ///! Huh.
    |     ^^^^^^^^^
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 45054c37c40..a717d8ccf28 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -1,3 +1,4 @@
+#![cfg_attr(bootstrap, feature(trait_upcasting))]
 #![feature(rustc_private)]
 #![feature(cell_update)]
 #![feature(float_gamma)]
@@ -9,7 +10,6 @@
 #![feature(yeet_expr)]
 #![feature(nonzero_ops)]
 #![feature(let_chains)]
-#![feature(trait_upcasting)]
 #![feature(strict_overflow_ops)]
 #![feature(pointer_is_aligned_to)]
 #![feature(unqualified_local_imports)]
diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
index f450e7e652c..1fd791a91f0 100644
--- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
+++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
@@ -1,9 +1,6 @@
 // Validation stops this too early.
 //@compile-flags: -Zmiri-disable-validation
 
-#![feature(trait_upcasting)]
-#![allow(incomplete_features)]
-
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     #[allow(dead_code)]
     fn a(&self) -> i32 {
diff --git a/src/tools/miri/tests/pass/binops.rs b/src/tools/miri/tests/pass/binops.rs
index 0988d7ccc4c..0aff7acb29d 100644
--- a/src/tools/miri/tests/pass/binops.rs
+++ b/src/tools/miri/tests/pass/binops.rs
@@ -2,23 +2,23 @@
 
 fn test_nil() {
     assert_eq!((), ());
-    assert!((!(() != ())));
-    assert!((!(() < ())));
-    assert!((() <= ()));
-    assert!((!(() > ())));
-    assert!((() >= ()));
+    assert!(!(() != ()));
+    assert!(!(() < ()));
+    assert!(() <= ());
+    assert!(!(() > ()));
+    assert!(() >= ());
 }
 
 fn test_bool() {
-    assert!((!(true < false)));
-    assert!((!(true <= false)));
-    assert!((true > false));
-    assert!((true >= false));
+    assert!(!(true < false));
+    assert!(!(true <= false));
+    assert!(true > false);
+    assert!(true >= false);
 
-    assert!((false < true));
-    assert!((false <= true));
-    assert!((!(false > true)));
-    assert!((!(false >= true)));
+    assert!(false < true);
+    assert!(false <= true);
+    assert!(!(false > true));
+    assert!(!(false >= true));
 
     // Bools support bitwise binops
     assert_eq!(false & false, false);
@@ -65,9 +65,9 @@ fn test_class() {
 
     assert_eq!(q, r);
     r.y = 17;
-    assert!((r.y != q.y));
+    assert!(r.y != q.y);
     assert_eq!(r.y, 17);
-    assert!((q != r));
+    assert!(q != r);
 }
 
 pub fn main() {
diff --git a/src/tools/miri/tests/pass/box-custom-alloc.rs b/src/tools/miri/tests/pass/box-custom-alloc.rs
index 71ce019187c..f0614313e50 100644
--- a/src/tools/miri/tests/pass/box-custom-alloc.rs
+++ b/src/tools/miri/tests/pass/box-custom-alloc.rs
@@ -1,7 +1,6 @@
 //@revisions: stack tree
 //@[tree]compile-flags: -Zmiri-tree-borrows
-#![allow(incomplete_features)] // for trait upcasting
-#![feature(allocator_api, trait_upcasting)]
+#![feature(allocator_api)]
 
 use std::alloc::{AllocError, Allocator, Layout};
 use std::cell::Cell;
diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs
index f100c4d6a86..6f8adc09640 100644
--- a/src/tools/miri/tests/pass/dyn-upcast.rs
+++ b/src/tools/miri/tests/pass/dyn-upcast.rs
@@ -1,6 +1,3 @@
-#![feature(trait_upcasting)]
-#![allow(incomplete_features)]
-
 use std::fmt;
 
 fn main() {
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index a639dc20a60..3688513987d 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -30,13 +30,18 @@ except ImportError:
 # These should be collaborators of the rust-lang/rust repository (with at least
 # read privileges on it). CI will fail otherwise.
 MAINTAINERS = {
-    "book": {"carols10cents"},
-    "nomicon": {"frewsxcv", "Gankra", "JohnTitor"},
-    "reference": {"Havvy", "matthewjasper", "ehuss"},
-    "rust-by-example": {"marioidival"},
-    "embedded-book": {"adamgreig", "andre-richter", "jamesmunns", "therealprof"},
+    "book": {"ehuss", "chriskrycho", "carols10cents"},
+    "nomicon": {"ehuss", "JohnTitor"},
+    "reference": {"ehuss"},
+    "rust-by-example": {"ehuss", "marioidival"},
+    "embedded-book": {
+        "ehuss",
+        "adamgreig",
+        "andre-richter",
+        "jamesmunns",
+        "therealprof",
+    },
     "edition-guide": {"ehuss"},
-    "rustc-dev-guide": {"spastorino", "amanjeev", "JohnTitor"},
 }
 
 LABELS = {
@@ -46,7 +51,6 @@ LABELS = {
     "rust-by-example": ["C-bug"],
     "embedded-book": ["C-bug"],
     "edition-guide": ["C-bug"],
-    "rustc-dev-guide": ["C-bug"],
 }
 
 REPOS = {
@@ -56,7 +60,6 @@ REPOS = {
     "rust-by-example": "https://github.com/rust-lang/rust-by-example",
     "embedded-book": "https://github.com/rust-embedded/book",
     "edition-guide": "https://github.com/rust-lang/edition-guide",
-    "rustc-dev-guide": "https://github.com/rust-lang/rustc-dev-guide",
 }
 
 
diff --git a/tests/codegen/debug-fndef-size.rs b/tests/codegen/debug-fndef-size.rs
index 27bf00adf0e..c58a8228967 100644
--- a/tests/codegen/debug-fndef-size.rs
+++ b/tests/codegen/debug-fndef-size.rs
@@ -1,4 +1,6 @@
-// Verify that `i32::cmp` FnDef type is declared with size 0 and align 1 in LLVM debuginfo.
+// Verify that `i32::cmp` FnDef type is declared with a size of 0 and an
+// alignment of 8 bits (1 byte) in LLVM debuginfo.
+
 //@ compile-flags: -O -g -Cno-prepopulate-passes
 //@ ignore-msvc the types are mangled differently
 
@@ -14,5 +16,5 @@ pub fn main() {
 
 // CHECK: %compare.dbg.spill = alloca [0 x i8], align 1
 // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %compare.dbg.spill, {{(metadata )?}}![[VAR:.*]], {{(metadata )?}}!DIExpression()
-// CHECK: ![[TYPE:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "fn(&i32, &i32) -> core::cmp::Ordering", baseType: !{{.*}}, align: 1, dwarfAddressSpace: {{.*}})
-// CHECK: ![[VAR]] = !DILocalVariable(name: "compare", scope: !{{.*}}, file: !{{.*}}, line: {{.*}}, type: ![[TYPE]], align: 1)
+// CHECK: ![[TYPE:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "fn(&i32, &i32) -> core::cmp::Ordering", baseType: !{{.*}}, align: 8, dwarfAddressSpace: {{.*}})
+// CHECK: ![[VAR]] = !DILocalVariable(name: "compare", scope: !{{.*}}, file: !{{.*}}, line: {{.*}}, type: ![[TYPE]], align: 8)
diff --git a/tests/codegen/terminating-catchpad.rs b/tests/codegen/terminating-catchpad.rs
new file mode 100644
index 00000000000..17d88796300
--- /dev/null
+++ b/tests/codegen/terminating-catchpad.rs
@@ -0,0 +1,37 @@
+//@ revisions: emscripten wasi seh
+//@[emscripten] compile-flags: --target wasm32-unknown-emscripten -Z emscripten-wasm-eh
+//@[wasi] compile-flags: --target wasm32-wasip1 -C panic=unwind
+//@[seh] compile-flags: --target x86_64-pc-windows-msvc
+//@[emscripten] needs-llvm-components: webassembly
+//@[wasi] needs-llvm-components: webassembly
+//@[seh] needs-llvm-components: x86
+
+// Ensure a catch-all generates:
+// - `catchpad ... [ptr null]` on Wasm (otherwise LLVM gets confused)
+// - `catchpad ... [ptr null, i32 64, ptr null]` on Windows (otherwise we catch SEH exceptions)
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+unsafe extern "C-unwind" {
+    safe fn unwinds();
+}
+
+#[lang = "panic_cannot_unwind"]
+fn panic_cannot_unwind() -> ! {
+    loop {}
+}
+
+#[no_mangle]
+#[rustc_nounwind]
+pub fn doesnt_unwind() {
+    // emscripten: %catchpad = catchpad within %catchswitch [ptr null]
+    // wasi: %catchpad = catchpad within %catchswitch [ptr null]
+    // seh: %catchpad = catchpad within %catchswitch [ptr null, i32 64, ptr null]
+    unwinds();
+}
diff --git a/tests/codegen/vtable-upcast.rs b/tests/codegen/vtable-upcast.rs
index ae7b4bf7aee..9e13e8dd68a 100644
--- a/tests/codegen/vtable-upcast.rs
+++ b/tests/codegen/vtable-upcast.rs
@@ -2,7 +2,6 @@
 //@ compile-flags: -C no-prepopulate-passes -Copt-level=0
 
 #![crate_type = "lib"]
-#![feature(trait_upcasting)]
 
 pub trait Base {
     fn base(&self);
diff --git a/tests/crashes/131886.rs b/tests/crashes/131886.rs
index c31c2d6aa8b..2c692dfb777 100644
--- a/tests/crashes/131886.rs
+++ b/tests/crashes/131886.rs
@@ -1,6 +1,6 @@
 //@ known-bug: #131886
 //@ compile-flags: -Zvalidate-mir --crate-type=lib
-#![feature(trait_upcasting, type_alias_impl_trait)]
+#![feature(type_alias_impl_trait)]
 
 type Tait = impl Sized;
 
diff --git a/tests/crashes/134336.rs b/tests/crashes/134336.rs
deleted file mode 100644
index 14b88e14f04..00000000000
--- a/tests/crashes/134336.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ known-bug: #134336
-#![expect(incomplete_features)]
-#![feature(explicit_tail_calls)]
-
-trait Tr {
-    fn f();
-}
-
-fn g<T: Tr>() {
-    become T::f();
-}
diff --git a/tests/run-make/libs-through-symlinks/rmake.rs b/tests/run-make/libs-through-symlinks/rmake.rs
index 4bb3d05abb7..894d6246445 100644
--- a/tests/run-make/libs-through-symlinks/rmake.rs
+++ b/tests/run-make/libs-through-symlinks/rmake.rs
@@ -21,6 +21,7 @@
 //! <https://github.com/rust-lang/rust/pull/13903>.
 
 //@ ignore-cross-compile
+//@ needs-symlink
 
 use run_make_support::{bare_rustc, cwd, path, rfs, rust_lib_name};
 
diff --git a/tests/ui/argument-suggestions/extern-fn-arg-names.stderr b/tests/ui/argument-suggestions/extern-fn-arg-names.stderr
index 47fbfc98c67..2aa4983624c 100644
--- a/tests/ui/argument-suggestions/extern-fn-arg-names.stderr
+++ b/tests/ui/argument-suggestions/extern-fn-arg-names.stderr
@@ -14,7 +14,7 @@ note: function defined here
   --> $DIR/extern-fn-arg-names.rs:2:8
    |
 LL |     fn dstfn(src: i32, dst: err);
-   |        ^^^^^
+   |        ^^^^^           ---
 help: provide the argument
    |
 LL |     dstfn(1, /* dst */);
diff --git a/tests/ui/binding/expr-match-generic.rs b/tests/ui/binding/expr-match-generic.rs
index 975eec42fd0..dcc069b9fb3 100644
--- a/tests/ui/binding/expr-match-generic.rs
+++ b/tests/ui/binding/expr-match-generic.rs
@@ -5,7 +5,7 @@ type compare<T> = extern "Rust" fn(T, T) -> bool;
 
 fn test_generic<T:Clone>(expected: T, eq: compare<T>) {
   let actual: T = match true { true => { expected.clone() }, _ => panic!("wat") };
-    assert!((eq(expected, actual)));
+    assert!(eq(expected, actual));
 }
 
 fn test_bool() {
diff --git a/tests/ui/binding/expr-match.rs b/tests/ui/binding/expr-match.rs
index 049beaaf51b..ce502ae1490 100644
--- a/tests/ui/binding/expr-match.rs
+++ b/tests/ui/binding/expr-match.rs
@@ -1,20 +1,17 @@
 //@ run-pass
 
-
-
-
 // Tests for using match as an expression
 
 fn test_basic() {
     let mut rs: bool = match true { true => { true } false => { false } };
-    assert!((rs));
+    assert!(rs);
     rs = match false { true => { false } false => { true } };
-    assert!((rs));
+    assert!(rs);
 }
 
 fn test_inferrence() {
     let rs = match true { true => { true } false => { false } };
-    assert!((rs));
+    assert!(rs);
 }
 
 fn test_alt_as_alt_head() {
@@ -25,7 +22,7 @@ fn test_alt_as_alt_head() {
           true => { false }
           false => { true }
         };
-    assert!((rs));
+    assert!(rs);
 }
 
 fn test_alt_as_block_result() {
@@ -34,7 +31,7 @@ fn test_alt_as_block_result() {
           true => { false }
           false => { match true { true => { true } false => { false } } }
         };
-    assert!((rs));
+    assert!(rs);
 }
 
 pub fn main() {
diff --git a/tests/ui/binop/binops.rs b/tests/ui/binop/binops.rs
index 0adbb49b14a..7142190a45b 100644
--- a/tests/ui/binop/binops.rs
+++ b/tests/ui/binop/binops.rs
@@ -5,23 +5,23 @@
 
 fn test_nil() {
     assert_eq!((), ());
-    assert!((!(() != ())));
-    assert!((!(() < ())));
-    assert!((() <= ()));
-    assert!((!(() > ())));
-    assert!((() >= ()));
+    assert!(!(() != ()));
+    assert!(!(() < ()));
+    assert!(() <= ());
+    assert!(!(() > ()));
+    assert!(() >= ());
 }
 
 fn test_bool() {
-    assert!((!(true < false)));
-    assert!((!(true <= false)));
-    assert!((true > false));
-    assert!((true >= false));
+    assert!(!(true < false));
+    assert!(!(true <= false));
+    assert!(true > false);
+    assert!(true >= false);
 
-    assert!((false < true));
-    assert!((false <= true));
-    assert!((!(false > true)));
-    assert!((!(false >= true)));
+    assert!(false < true);
+    assert!(false <= true);
+    assert!(!(false > true));
+    assert!(!(false >= true));
 
     // Bools support bitwise binops
     assert_eq!(false & false, false);
@@ -76,9 +76,9 @@ fn test_class() {
   }
   assert_eq!(q, r);
   r.y = 17;
-  assert!((r.y != q.y));
+  assert!(r.y != q.y);
   assert_eq!(r.y, 17);
-  assert!((q != r));
+  assert!(q != r);
 }
 
 pub fn main() {
diff --git a/tests/ui/binop/structured-compare.rs b/tests/ui/binop/structured-compare.rs
index 164760cd7a0..7d1eff45302 100644
--- a/tests/ui/binop/structured-compare.rs
+++ b/tests/ui/binop/structured-compare.rs
@@ -17,14 +17,14 @@ pub fn main() {
     let a = (1, 2, 3);
     let b = (1, 2, 3);
     assert_eq!(a, b);
-    assert!((a != (1, 2, 4)));
-    assert!((a < (1, 2, 4)));
-    assert!((a <= (1, 2, 4)));
-    assert!(((1, 2, 4) > a));
-    assert!(((1, 2, 4) >= a));
+    assert!(a != (1, 2, 4));
+    assert!(a < (1, 2, 4));
+    assert!(a <= (1, 2, 4));
+    assert!((1, 2, 4) > a);
+    assert!((1, 2, 4) >= a);
     let x = foo::large;
     let y = foo::small;
-    assert!((x != y));
+    assert!(x != y);
     assert_eq!(x, foo::large);
-    assert!((x != foo::small));
+    assert!(x != foo::small);
 }
diff --git a/tests/ui/c-variadic/variadic-ffi-1.stderr b/tests/ui/c-variadic/variadic-ffi-1.stderr
index 7a54d043356..7eca4cb61bc 100644
--- a/tests/ui/c-variadic/variadic-ffi-1.stderr
+++ b/tests/ui/c-variadic/variadic-ffi-1.stderr
@@ -14,7 +14,7 @@ note: function defined here
   --> $DIR/variadic-ffi-1.rs:15:8
    |
 LL |     fn foo(f: isize, x: u8, ...);
-   |        ^^^
+   |        ^^^ -         -
 help: provide the arguments
    |
 LL |         foo(/* isize */, /* u8 */);
@@ -30,7 +30,7 @@ note: function defined here
   --> $DIR/variadic-ffi-1.rs:15:8
    |
 LL |     fn foo(f: isize, x: u8, ...);
-   |        ^^^
+   |        ^^^           -
 help: provide the argument
    |
 LL |         foo(1, /* u8 */);
diff --git a/tests/ui/cfg/conditional-compile.rs b/tests/ui/cfg/conditional-compile.rs
index a4f334dd696..dff280054d6 100644
--- a/tests/ui/cfg/conditional-compile.rs
+++ b/tests/ui/cfg/conditional-compile.rs
@@ -85,7 +85,7 @@ pub fn main() {
 pub fn main() {
     // Exercise some of the configured items in ways that wouldn't be possible
     // if they had the FALSE definition
-    assert!((b));
+    assert!(b);
     let _x: t = true;
     let _y: tg = tg::bar;
 
diff --git a/tests/ui/codegen/issue-99551.rs b/tests/ui/codegen/issue-99551.rs
index 9bacbaa6edc..f498718310d 100644
--- a/tests/ui/codegen/issue-99551.rs
+++ b/tests/ui/codegen/issue-99551.rs
@@ -1,5 +1,4 @@
 //@ build-pass
-#![feature(trait_upcasting)]
 
 pub trait A {}
 pub trait B {}
diff --git a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs
index a4eb669e321..1702fc1ed49 100644
--- a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs
+++ b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs
@@ -1,5 +1,5 @@
-#![feature(dyn_star, trait_upcasting)]
-//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+#![expect(incomplete_features)]
+#![feature(dyn_star)]
 
 trait A: B {}
 trait B {}
diff --git a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
index 1f7bfb1d5bd..289d85072e6 100644
--- a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
+++ b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
@@ -1,12 +1,3 @@
-warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/no-unsize-coerce-dyn-trait.rs:1:12
-   |
-LL | #![feature(dyn_star, trait_upcasting)]
-   |            ^^^^^^^^
-   |
-   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
 error[E0308]: mismatched types
   --> $DIR/no-unsize-coerce-dyn-trait.rs:11:26
    |
@@ -18,6 +9,6 @@ LL |     let y: Box<dyn* B> = x;
    = note: expected struct `Box<dyn* B>`
               found struct `Box<dyn* A>`
 
-error: aborting due to 1 previous error; 1 warning emitted
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/dyn-star/upcast.rs b/tests/ui/dyn-star/upcast.rs
index e8e89fc5101..01e1b94f87e 100644
--- a/tests/ui/dyn-star/upcast.rs
+++ b/tests/ui/dyn-star/upcast.rs
@@ -1,6 +1,6 @@
 //@ known-bug: #104800
 
-#![feature(dyn_star, trait_upcasting)]
+#![feature(dyn_star)]
 
 trait Foo: Bar {
     fn hello(&self);
diff --git a/tests/ui/dyn-star/upcast.stderr b/tests/ui/dyn-star/upcast.stderr
index 801e1c233c1..3f244d4b6ae 100644
--- a/tests/ui/dyn-star/upcast.stderr
+++ b/tests/ui/dyn-star/upcast.stderr
@@ -1,7 +1,7 @@
 warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/upcast.rs:3:12
    |
-LL | #![feature(dyn_star, trait_upcasting)]
+LL | #![feature(dyn_star)]
    |            ^^^^^^^^
    |
    = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
diff --git a/tests/ui/error-codes/E0060.stderr b/tests/ui/error-codes/E0060.stderr
index 8387b15b970..aadf1ea93cb 100644
--- a/tests/ui/error-codes/E0060.stderr
+++ b/tests/ui/error-codes/E0060.stderr
@@ -8,7 +8,7 @@ note: function defined here
   --> $DIR/E0060.rs:2:8
    |
 LL |     fn printf(_: *const u8, ...) -> u32;
-   |        ^^^^^^
+   |        ^^^^^^ -
 help: provide the argument
    |
 LL |     unsafe { printf(/* *const u8 */); }
diff --git a/tests/ui/explicit-tail-calls/become-trait-fn.rs b/tests/ui/explicit-tail-calls/become-trait-fn.rs
new file mode 100644
index 00000000000..03255f15dd0
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/become-trait-fn.rs
@@ -0,0 +1,19 @@
+// regression test for <https://github.com/rust-lang/rust/issues/134336>
+// this previously caused an ICE, because we would compare `#[track_caller]` of
+// the callee and the caller (in tailcalls specifically), leading to a problem
+// since `T::f`'s instance can't be resolved (we do not know if the function is
+// or isn't marked with `#[track_caller]`!)
+//
+//@ check-pass
+#![expect(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+trait Tr {
+    fn f();
+}
+
+fn g<T: Tr>() {
+    become T::f();
+}
+
+fn main() {}
diff --git a/tests/ui/explicit-tail-calls/callee_is_track_caller.rs b/tests/ui/explicit-tail-calls/callee_is_track_caller.rs
new file mode 100644
index 00000000000..bcb93fda8c8
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/callee_is_track_caller.rs
@@ -0,0 +1,15 @@
+//@ check-pass
+// FIXME(explicit_tail_calls): make this run-pass, once tail calls are properly implemented
+#![expect(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+fn a(x: u32) -> u32 {
+    become b(x);
+}
+
+#[track_caller]
+fn b(x: u32) -> u32 { x + 42 }
+
+fn main() {
+    assert_eq!(a(12), 54);
+}
diff --git a/tests/ui/explicit-tail-calls/caller_is_track_caller.rs b/tests/ui/explicit-tail-calls/caller_is_track_caller.rs
new file mode 100644
index 00000000000..4e5f3f12f83
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/caller_is_track_caller.rs
@@ -0,0 +1,16 @@
+#![expect(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+#[track_caller]
+fn a() {
+    become b(); //~ error: a function marked with `#[track_caller]` cannot perform a tail-call
+}
+
+fn b() {}
+
+#[track_caller]
+fn c() {
+    become a(); //~ error: a function marked with `#[track_caller]` cannot perform a tail-call
+}
+
+fn main() {}
diff --git a/tests/ui/explicit-tail-calls/caller_is_track_caller.stderr b/tests/ui/explicit-tail-calls/caller_is_track_caller.stderr
new file mode 100644
index 00000000000..79b9b45986c
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/caller_is_track_caller.stderr
@@ -0,0 +1,14 @@
+error: a function marked with `#[track_caller]` cannot perform a tail-call
+  --> $DIR/caller_is_track_caller.rs:6:5
+   |
+LL |     become b();
+   |     ^^^^^^^^^^
+
+error: a function marked with `#[track_caller]` cannot perform a tail-call
+  --> $DIR/caller_is_track_caller.rs:13:5
+   |
+LL |     become a();
+   |     ^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/expr/block.rs b/tests/ui/expr/block.rs
index bf626c9ead3..70f5c274c21 100644
--- a/tests/ui/expr/block.rs
+++ b/tests/ui/expr/block.rs
@@ -4,7 +4,7 @@
 
 // Tests for standalone blocks as expressions
 
-fn test_basic() { let rs: bool = { true }; assert!((rs)); }
+fn test_basic() { let rs: bool = { true }; assert!(rs); }
 
 struct RS { v1: isize, v2: isize }
 
diff --git a/tests/ui/expr/if/expr-if.rs b/tests/ui/expr/if/expr-if.rs
index ae869c4b77a..68c2fc22130 100644
--- a/tests/ui/expr/if/expr-if.rs
+++ b/tests/ui/expr/if/expr-if.rs
@@ -1,43 +1,43 @@
 //@ run-pass
 // Tests for if as expressions
 
-fn test_if() { let rs: bool = if true { true } else { false }; assert!((rs)); }
+fn test_if() { let rs: bool = if true { true } else { false }; assert!(rs); }
 
 fn test_else() {
     let rs: bool = if false { false } else { true };
-    assert!((rs));
+    assert!(rs);
 }
 
 fn test_elseif1() {
     let rs: bool = if true { true } else if true { false } else { false };
-    assert!((rs));
+    assert!(rs);
 }
 
 fn test_elseif2() {
     let rs: bool = if false { false } else if true { true } else { false };
-    assert!((rs));
+    assert!(rs);
 }
 
 fn test_elseif3() {
     let rs: bool = if false { false } else if false { false } else { true };
-    assert!((rs));
+    assert!(rs);
 }
 
 fn test_inferrence() {
     let rs = if true { true } else { false };
-    assert!((rs));
+    assert!(rs);
 }
 
 fn test_if_as_if_condition() {
     let rs1 = if if false { false } else { true } { true } else { false };
-    assert!((rs1));
+    assert!(rs1);
     let rs2 = if if true { false } else { true } { false } else { true };
-    assert!((rs2));
+    assert!(rs2);
 }
 
 fn test_if_as_block_result() {
     let rs = if true { if false { false } else { true } } else { false };
-    assert!((rs));
+    assert!(rs);
 }
 
 pub fn main() {
diff --git a/tests/ui/feature-gates/feature-gate-trait_upcasting.rs b/tests/ui/feature-gates/feature-gate-trait_upcasting.rs
deleted file mode 100644
index e4102f1cfa7..00000000000
--- a/tests/ui/feature-gates/feature-gate-trait_upcasting.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-trait Foo {}
-
-trait Bar: Foo {}
-
-impl Foo for () {}
-
-impl Bar for () {}
-
-fn main() {
-    let bar: &dyn Bar = &();
-    let foo: &dyn Foo = bar;
-    //~^ ERROR trait upcasting coercion is experimental [E0658]
-}
diff --git a/tests/ui/feature-gates/feature-gate-trait_upcasting.stderr b/tests/ui/feature-gates/feature-gate-trait_upcasting.stderr
deleted file mode 100644
index 6fd277ae8cc..00000000000
--- a/tests/ui/feature-gates/feature-gate-trait_upcasting.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0658]: cannot cast `dyn Bar` to `dyn Foo`, trait upcasting coercion is experimental
-  --> $DIR/feature-gate-trait_upcasting.rs:11:25
-   |
-LL |     let foo: &dyn Foo = bar;
-   |                         ^^^
-   |
-   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
-   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = note: required when coercing `&dyn Bar` into `&dyn Foo`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/fn/param-mismatch-foreign.rs b/tests/ui/fn/param-mismatch-foreign.rs
new file mode 100644
index 00000000000..2ab2bf95448
--- /dev/null
+++ b/tests/ui/fn/param-mismatch-foreign.rs
@@ -0,0 +1,11 @@
+extern "C" {
+    fn foo(x: i32, y: u32, z: i32);
+    //~^ NOTE function defined here
+}
+
+fn main() {
+    foo(1i32, 2i32);
+    //~^ ERROR this function takes 3 arguments but 2 arguments were supplied
+    //~| NOTE argument #2 of type `u32` is missing
+    //~| HELP provide the argument
+}
diff --git a/tests/ui/fn/param-mismatch-foreign.stderr b/tests/ui/fn/param-mismatch-foreign.stderr
new file mode 100644
index 00000000000..1182908891c
--- /dev/null
+++ b/tests/ui/fn/param-mismatch-foreign.stderr
@@ -0,0 +1,19 @@
+error[E0061]: this function takes 3 arguments but 2 arguments were supplied
+  --> $DIR/param-mismatch-foreign.rs:7:5
+   |
+LL |     foo(1i32, 2i32);
+   |     ^^^       ---- argument #2 of type `u32` is missing
+   |
+note: function defined here
+  --> $DIR/param-mismatch-foreign.rs:2:8
+   |
+LL |     fn foo(x: i32, y: u32, z: i32);
+   |        ^^^         -
+help: provide the argument
+   |
+LL |     foo(1i32, /* u32 */, 2i32);
+   |        ~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0061`.
diff --git a/tests/ui/for-loop-while/break.rs b/tests/ui/for-loop-while/break.rs
index 77774792262..442e07e148c 100644
--- a/tests/ui/for-loop-while/break.rs
+++ b/tests/ui/for-loop-while/break.rs
@@ -8,18 +8,18 @@ pub fn main() {
     assert_eq!(i, 20);
     let xs = [1, 2, 3, 4, 5, 6];
     for x in &xs {
-        if *x == 3 { break; } assert!((*x <= 3));
+        if *x == 3 { break; } assert!(*x <= 3);
     }
     i = 0;
-    while i < 10 { i += 1; if i % 2 == 0 { continue; } assert!((i % 2 != 0)); }
+    while i < 10 { i += 1; if i % 2 == 0 { continue; } assert!(i % 2 != 0); }
     i = 0;
     loop {
-        i += 1; if i % 2 == 0 { continue; } assert!((i % 2 != 0));
+        i += 1; if i % 2 == 0 { continue; } assert!(i % 2 != 0);
         if i >= 10 { break; }
     }
     let ys = vec![1, 2, 3, 4, 5, 6];
     for x in &ys {
         if *x % 2 == 0 { continue; }
-        assert!((*x % 2 != 0));
+        assert!(*x % 2 != 0);
     }
 }
diff --git a/tests/ui/for-loop-while/while-cont.rs b/tests/ui/for-loop-while/while-cont.rs
index 1640b7e1803..73a08c26f9a 100644
--- a/tests/ui/for-loop-while/while-cont.rs
+++ b/tests/ui/for-loop-while/while-cont.rs
@@ -3,7 +3,7 @@
 pub fn main() {
     let mut i = 1;
     while i > 0 {
-        assert!((i > 0));
+        assert!(i > 0);
         println!("{}", i);
         i -= 1;
         continue;
diff --git a/tests/ui/for-loop-while/while-loop-constraints-2.rs b/tests/ui/for-loop-while/while-loop-constraints-2.rs
index 654f6769902..1d2d9c2ecfe 100644
--- a/tests/ui/for-loop-while/while-loop-constraints-2.rs
+++ b/tests/ui/for-loop-while/while-loop-constraints-2.rs
@@ -11,5 +11,5 @@ pub fn main() {
         while false { x = y; y = z; }
         println!("{}", y);
     }
-    assert!((y == 42 && z == 50));
+    assert!(y == 42 && z == 50);
 }
diff --git a/tests/ui/generics/generic-tag-match.rs b/tests/ui/generics/generic-tag-match.rs
index dd0291e9d87..378b51df287 100644
--- a/tests/ui/generics/generic-tag-match.rs
+++ b/tests/ui/generics/generic-tag-match.rs
@@ -7,7 +7,7 @@ enum foo<T> { arm(T), }
 fn altfoo<T>(f: foo<T>) {
     let mut hit = false;
     match f { foo::arm::<T>(_x) => { println!("in arm"); hit = true; } }
-    assert!((hit));
+    assert!(hit);
 }
 
 pub fn main() { altfoo::<isize>(foo::arm::<isize>(10)); }
diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs b/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs
new file mode 100644
index 00000000000..6f7e1a0eaef
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+
+// Ensure that we skip uncaptured args from RPITITs when comptuing outlives.
+
+#![feature(precise_capturing_in_traits)]
+
+struct Invariant<T>(*mut T);
+
+trait Foo {
+    fn hello<'s: 's>(&'s self) -> Invariant<impl Sized + use<Self>>;
+}
+
+fn outlives_static(_: impl Sized + 'static) {}
+
+fn hello<'s, T: Foo + 'static>(x: &'s T) {
+    outlives_static(x.hello());
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs b/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs
new file mode 100644
index 00000000000..94d81d766f7
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs
@@ -0,0 +1,18 @@
+//@ check-pass
+
+// Ensure that we skip uncaptured args from RPITITs when collecting the regions
+// to enforce member constraints in opaque type inference.
+
+#![feature(precise_capturing_in_traits)]
+
+struct Invariant<T>(*mut T);
+
+trait Foo {
+    fn hello<'s: 's>(&'s self) -> Invariant<impl Sized + use<Self>>;
+}
+
+fn hello<'s, T: Foo>(x: &'s T) -> Invariant<impl Sized> {
+    x.hello()
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/unsized_coercion5.old.stderr b/tests/ui/impl-trait/unsized_coercion5.old.stderr
index e56c026b037..72aa92ef6b9 100644
--- a/tests/ui/impl-trait/unsized_coercion5.old.stderr
+++ b/tests/ui/impl-trait/unsized_coercion5.old.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time
-  --> $DIR/unsized_coercion5.rs:17:32
+  --> $DIR/unsized_coercion5.rs:15:32
    |
 LL |         let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
    |                                ^ doesn't have a size known at compile-time
diff --git a/tests/ui/impl-trait/unsized_coercion5.rs b/tests/ui/impl-trait/unsized_coercion5.rs
index 81f8a6afe9a..51ae4f20671 100644
--- a/tests/ui/impl-trait/unsized_coercion5.rs
+++ b/tests/ui/impl-trait/unsized_coercion5.rs
@@ -5,8 +5,6 @@
 //@[next] compile-flags: -Znext-solver
 //@[next] check-pass
 
-#![feature(trait_upcasting)]
-
 trait Trait {}
 
 impl Trait for u32 {}
diff --git a/tests/ui/iterators/iter-range.rs b/tests/ui/iterators/iter-range.rs
index 9594729c06c..ec993317539 100644
--- a/tests/ui/iterators/iter-range.rs
+++ b/tests/ui/iterators/iter-range.rs
@@ -2,7 +2,7 @@
 
 
 fn range_<F>(a: isize, b: isize, mut it: F) where F: FnMut(isize) {
-    assert!((a < b));
+    assert!(a < b);
     let mut i: isize = a;
     while i < b { it(i); i += 1; }
 }
diff --git a/tests/ui/linkage-attr/linkage-attr-does-not-panic-llvm-issue-33992.rs b/tests/ui/linkage-attr/linkage-attr-does-not-panic-llvm-issue-33992.rs
index df73eddd8d5..0717a2d5a6c 100644
--- a/tests/ui/linkage-attr/linkage-attr-does-not-panic-llvm-issue-33992.rs
+++ b/tests/ui/linkage-attr/linkage-attr-does-not-panic-llvm-issue-33992.rs
@@ -18,9 +18,6 @@ pub static TEST4: bool = true;
 #[linkage = "linkonce_odr"]
 pub static TEST5: bool = true;
 
-#[linkage = "private"]
-pub static TEST6: bool = true;
-
 #[linkage = "weak"]
 pub static TEST7: bool = true;
 
diff --git a/tests/ui/macros/syntax-extension-source-utils.rs b/tests/ui/macros/syntax-extension-source-utils.rs
index a16ebdc7504..2f88e508058 100644
--- a/tests/ui/macros/syntax-extension-source-utils.rs
+++ b/tests/ui/macros/syntax-extension-source-utils.rs
@@ -16,7 +16,7 @@ pub fn main() {
     assert_eq!(line!(), 16);
     assert_eq!(column!(), 16);
     assert_eq!(indirect_line!(), 18);
-    assert!((file!().ends_with("syntax-extension-source-utils.rs")));
+    assert!(file!().ends_with("syntax-extension-source-utils.rs"));
     assert_eq!(stringify!((2*3) + 5).to_string(), "(2*3) + 5".to_string());
     assert!(include!("syntax-extension-source-utils-files/includeme.\
                       fragment").to_string()
@@ -30,7 +30,7 @@ pub fn main() {
         include_bytes!("syntax-extension-source-utils-files/includeme.fragment")
         [1] == (42 as u8)); // '*'
     // The Windows tests are wrapped in an extra module for some reason
-    assert!((m1::m2::where_am_i().ends_with("m1::m2")));
+    assert!(m1::m2::where_am_i().ends_with("m1::m2"));
 
     assert_eq!((35, "(2*3) + 5"), (line!(), stringify!((2*3) + 5)));
 }
diff --git a/tests/ui/mismatched_types/issue-26480.stderr b/tests/ui/mismatched_types/issue-26480.stderr
index ae10a00671e..da8d73225f3 100644
--- a/tests/ui/mismatched_types/issue-26480.stderr
+++ b/tests/ui/mismatched_types/issue-26480.stderr
@@ -13,7 +13,7 @@ note: function defined here
   --> $DIR/issue-26480.rs:2:8
    |
 LL |     fn write(fildes: i32, buf: *const i8, nbyte: u64) -> i64;
-   |        ^^^^^
+   |        ^^^^^                              -----
    = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit
    |
diff --git a/tests/ui/never_type/dont-suggest-turbofish-from-expansion.rs b/tests/ui/never_type/dont-suggest-turbofish-from-expansion.rs
new file mode 100644
index 00000000000..9a53358464d
--- /dev/null
+++ b/tests/ui/never_type/dont-suggest-turbofish-from-expansion.rs
@@ -0,0 +1,20 @@
+#![deny(dependency_on_unit_never_type_fallback)]
+
+fn create_ok_default<C>() -> Result<C, ()>
+where
+    C: Default,
+{
+    Ok(C::default())
+}
+
+fn main() -> Result<(), ()> {
+    //~^ ERROR this function depends on never type fallback being `()`
+    //~| WARN this was previously accepted by the compiler but is being phased out
+    let (returned_value, _) = (|| {
+        let created = create_ok_default()?;
+        Ok((created, ()))
+    })()?;
+
+    let _ = format_args!("{:?}", returned_value);
+    Ok(())
+}
diff --git a/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr b/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr
new file mode 100644
index 00000000000..3fe642a8401
--- /dev/null
+++ b/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr
@@ -0,0 +1,26 @@
+error: this function depends on never type fallback being `()`
+  --> $DIR/dont-suggest-turbofish-from-expansion.rs:10:1
+   |
+LL | fn main() -> Result<(), ()> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+   = help: specify the types explicitly
+note: in edition 2024, the requirement `!: Default` will fail
+  --> $DIR/dont-suggest-turbofish-from-expansion.rs:14:23
+   |
+LL |         let created = create_ok_default()?;
+   |                       ^^^^^^^^^^^^^^^^^^^
+note: the lint level is defined here
+  --> $DIR/dont-suggest-turbofish-from-expansion.rs:1:9
+   |
+LL | #![deny(dependency_on_unit_never_type_fallback)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: use `()` annotations to avoid fallback changes
+   |
+LL |         let created: () = create_ok_default()?;
+   |                    ++++
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
index 04cd2fcafd6..49b966f32ce 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
@@ -130,10 +130,6 @@ LL |         msg_send!();
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
    = note: this warning originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: use `()` annotations to avoid fallback changes
-   |
-LL |             match send_message::<() /* ?0 */>() {
-   |                                  ~~
 
 warning: 10 warnings emitted
 
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
index 7adba2cc709..4d3692a7b04 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
@@ -130,10 +130,6 @@ LL |         msg_send!();
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
    = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: use `()` annotations to avoid fallback changes
-   |
-LL |             match send_message::<() /* ?0 */>() {
-   |                                  ~~
 
 warning: the type `!` does not permit zero-initialization
   --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:12:18
diff --git a/tests/ui/numbers-arithmetic/arith-unsigned.rs b/tests/ui/numbers-arithmetic/arith-unsigned.rs
index 5a285ceca32..4a1bae438ca 100644
--- a/tests/ui/numbers-arithmetic/arith-unsigned.rs
+++ b/tests/ui/numbers-arithmetic/arith-unsigned.rs
@@ -3,22 +3,22 @@
 
 // Unsigned integer operations
 pub fn main() {
-    assert!((0u8 < 255u8));
-    assert!((0u8 <= 255u8));
-    assert!((255u8 > 0u8));
-    assert!((255u8 >= 0u8));
+    assert!(0u8 < 255u8);
+    assert!(0u8 <= 255u8);
+    assert!(255u8 > 0u8);
+    assert!(255u8 >= 0u8);
     assert_eq!(250u8 / 10u8, 25u8);
     assert_eq!(255u8 % 10u8, 5u8);
-    assert!((0u16 < 60000u16));
-    assert!((0u16 <= 60000u16));
-    assert!((60000u16 > 0u16));
-    assert!((60000u16 >= 0u16));
+    assert!(0u16 < 60000u16);
+    assert!(0u16 <= 60000u16);
+    assert!(60000u16 > 0u16);
+    assert!(60000u16 >= 0u16);
     assert_eq!(60000u16 / 10u16, 6000u16);
     assert_eq!(60005u16 % 10u16, 5u16);
-    assert!((0u32 < 4000000000u32));
-    assert!((0u32 <= 4000000000u32));
-    assert!((4000000000u32 > 0u32));
-    assert!((4000000000u32 >= 0u32));
+    assert!(0u32 < 4000000000u32);
+    assert!(0u32 <= 4000000000u32);
+    assert!(4000000000u32 > 0u32);
+    assert!(4000000000u32 >= 0u32);
     assert_eq!(4000000000u32 / 10u32, 400000000u32);
     assert_eq!(4000000005u32 % 10u32, 5u32);
     // 64-bit numbers have some flakiness yet. Not tested
diff --git a/tests/ui/numbers-arithmetic/float-nan.rs b/tests/ui/numbers-arithmetic/float-nan.rs
index 7d1af0155da..ee3718f6f93 100644
--- a/tests/ui/numbers-arithmetic/float-nan.rs
+++ b/tests/ui/numbers-arithmetic/float-nan.rs
@@ -2,7 +2,7 @@
 
 pub fn main() {
   let nan: f64 = f64::NAN;
-  assert!((nan).is_nan());
+  assert!(nan.is_nan());
 
   let inf: f64 = f64::INFINITY;
   let neg_inf: f64 = -f64::INFINITY;
diff --git a/tests/ui/numbers-arithmetic/float2.rs b/tests/ui/numbers-arithmetic/float2.rs
index 1b7add01cc6..515220fee9f 100644
--- a/tests/ui/numbers-arithmetic/float2.rs
+++ b/tests/ui/numbers-arithmetic/float2.rs
@@ -15,12 +15,12 @@ pub fn main() {
     let j = 3.1e+9f64;
     let k = 3.2e-10f64;
     assert_eq!(a, b);
-    assert!((c < b));
+    assert!(c < b);
     assert_eq!(c, d);
-    assert!((e < g));
-    assert!((f < h));
+    assert!(e < g);
+    assert!(f < h);
     assert_eq!(g, 1000000.0f32);
     assert_eq!(h, i);
-    assert!((j > k));
-    assert!((k < a));
+    assert!(j > k);
+    assert!(k < a);
 }
diff --git a/tests/ui/numbers-arithmetic/floatlits.rs b/tests/ui/numbers-arithmetic/floatlits.rs
index 21f19b69c49..2dab2242011 100644
--- a/tests/ui/numbers-arithmetic/floatlits.rs
+++ b/tests/ui/numbers-arithmetic/floatlits.rs
@@ -4,9 +4,9 @@
 
 pub fn main() {
     let f = 4.999999999999f64;
-    assert!((f > 4.90f64));
-    assert!((f < 5.0f64));
+    assert!(f > 4.90f64);
+    assert!(f < 5.0f64);
     let g = 4.90000000001e-10f64;
-    assert!((g > 5e-11f64));
-    assert!((g < 5e-9f64));
+    assert!(g > 5e-11f64);
+    assert!(g < 5e-9f64);
 }
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr
index 70cdcbd62eb..b7fb70dfd24 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:60:10
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:54:10
    |
 LL |     let [&mut ref x] = &[&mut 0];
    |          ^^^^^
@@ -10,55 +10,75 @@ help: replace this `&mut` pattern with `&`
 LL |     let [&ref x] = &[&mut 0];
    |          ~
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:67:10
    |
 LL |     let [ref mut x] = &[0];
-   |          ^^^^^^^ cannot override to bind by-reference when that is the implicit default
+   |          ^^^^^^^ binding modifier not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:67:9
+   |
+LL |     let [ref mut x] = &[0];
+   |         ^^^^^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL |     let &[ref mut x] = &[0];
    |         +
 
 error[E0596]: cannot borrow data in a `&` reference as mutable
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:67:10
    |
 LL |     let [ref mut x] = &[0];
    |          ^^^^^^^^^ cannot borrow as mutable
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:83:10
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:75:10
    |
 LL |     let [ref x] = &[0];
-   |          ^^^ cannot override to bind by-reference when that is the implicit default
+   |          ^^^ binding modifier not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:75:9
+   |
+LL |     let [ref x] = &[0];
+   |         ^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL |     let &[ref x] = &[0];
    |         +
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:88:10
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:79:10
    |
 LL |     let [ref x] = &mut [0];
-   |          ^^^ cannot override to bind by-reference when that is the implicit default
+   |          ^^^ binding modifier not allowed under `ref mut` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:79:9
+   |
+LL |     let [ref x] = &mut [0];
+   |         ^^^^^^^ this matches on type `&mut _`
 help: make the implied reference pattern explicit
    |
 LL |     let &mut [ref x] = &mut [0];
    |         ++++
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:93:10
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:83:10
    |
 LL |     let [ref mut x] = &mut [0];
-   |          ^^^^^^^ cannot override to bind by-reference when that is the implicit default
+   |          ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:83:9
+   |
+LL |     let [ref mut x] = &mut [0];
+   |         ^^^^^^^^^^^ this matches on type `&mut _`
 help: make the implied reference pattern explicit
    |
 LL |     let &mut [ref mut x] = &mut [0];
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs
index 4c88c0c63ae..4e048570c33 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs
@@ -13,26 +13,22 @@
 /// The eat-outer variant eats the inherited reference, so binding with `ref` isn't a problem.
 fn errors_from_eating_the_real_reference() {
     let [&ref x] = &[&0];
-    //[structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
-    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    //[structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move`
     #[cfg(stable2021)] let _: &u32 = x;
     #[cfg(classic2024)] let _: &&u32 = x;
 
     let [&ref x] = &mut [&0];
-    //[structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
-    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    //[structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move`
     #[cfg(stable2021)] let _: &u32 = x;
     #[cfg(classic2024)] let _: &&u32 = x;
 
     let [&mut ref x] = &mut [&mut 0];
-    //[structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
-    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    //[structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move`
     #[cfg(stable2021)] let _: &u32 = x;
     #[cfg(classic2024)] let _: &&mut u32 = x;
 
     let [&mut ref mut x] = &mut [&mut 0];
-    //[structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
-    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    //[structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move`
     #[cfg(stable2021)] let _: &mut u32 = x;
     #[cfg(classic2024)] let _: &mut &mut u32 = x;
 }
@@ -43,15 +39,13 @@ fn errors_from_eating_the_real_reference_caught_in_hir_typeck_on_stable() {
     let [&ref x] = &[&mut 0];
     //[stable2021]~^ ERROR: mismatched types
     //[stable2021]~| types differ in mutability
-    //[structural2024]~^^^ ERROR: this pattern relies on behavior which may change in edition 2024
-    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    //[structural2024]~^^^ ERROR: binding modifiers may only be written when the default binding mode is `move`
     #[cfg(classic2024)] let _: &&mut u32 = x;
 
     let [&ref x] = &mut [&mut 0];
     //[stable2021]~^ ERROR: mismatched types
     //[stable2021]~| types differ in mutability
-    //[structural2024]~^^^ ERROR: this pattern relies on behavior which may change in edition 2024
-    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    //[structural2024]~^^^ ERROR: binding modifiers may only be written when the default binding mode is `move`
     #[cfg(classic2024)] let _: &&mut u32 = x;
 }
 
@@ -60,8 +54,7 @@ fn errors_dependent_on_eating_order_caught_in_hir_typeck_when_eating_outer() {
     let [&mut ref x] = &[&mut 0];
     //[classic2024]~^ ERROR: mismatched types
     //[classic2024]~| cannot match inherited `&` with `&mut` pattern
-    //[structural2024]~^^^ ERROR: this pattern relies on behavior which may change in edition 2024
-    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    //[structural2024]~^^^ ERROR: binding modifiers may only be written when the default binding mode is `move`
     #[cfg(stable2021)] let _: &u32 = x;
 }
 
@@ -73,25 +66,21 @@ fn errors_dependent_on_eating_order_caught_in_hir_typeck_when_eating_outer() {
 fn borrowck_errors_in_old_editions() {
     let [ref mut x] = &[0];
     //~^ ERROR: cannot borrow data in a `&` reference as mutable
-    //[classic2024,structural2024]~| ERROR: this pattern relies on behavior which may change in edition 2024
-    //[classic2024,structural2024]~| cannot override to bind by-reference when that is the implicit default
+    //[classic2024,structural2024]~| ERROR: binding modifiers may only be written when the default binding mode is `move`
 }
 
 /// The remaining tests are purely for testing `ref` bindings in the presence of an inherited
 /// reference. These should always fail on edition 2024 and succeed on edition 2021.
 pub fn main() {
     let [ref x] = &[0];
-    //[classic2024,structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
-    //[classic2024,structural2024]~| cannot override to bind by-reference when that is the implicit default
+    //[classic2024,structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move`
     #[cfg(stable2021)] let _: &u32 = x;
 
     let [ref x] = &mut [0];
-    //[classic2024,structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
-    //[classic2024,structural2024]~| cannot override to bind by-reference when that is the implicit default
+    //[classic2024,structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move`
     #[cfg(stable2021)] let _: &u32 = x;
 
     let [ref mut x] = &mut [0];
-    //[classic2024,structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
-    //[classic2024,structural2024]~| cannot override to bind by-reference when that is the implicit default
+    //[classic2024,structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move`
     #[cfg(stable2021)] let _: &mut u32 = x;
 }
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr
index a21e4bb5b8f..26095d84605 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:43:10
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:39:10
    |
 LL |     let [&ref x] = &[&mut 0];
    |          ^^^^^^    --------- this expression has type `&[&mut {integer}; 1]`
@@ -15,7 +15,7 @@ LL +     let [ref x] = &[&mut 0];
    |
 
 error[E0308]: mismatched types
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:50:10
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:45:10
    |
 LL |     let [&ref x] = &mut [&mut 0];
    |          ^^^^^^    ------------- this expression has type `&mut [&mut {integer}; 1]`
@@ -31,7 +31,7 @@ LL +     let [ref x] = &mut [&mut 0];
    |
 
 error[E0596]: cannot borrow data in a `&` reference as mutable
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:67:10
    |
 LL |     let [ref mut x] = &[0];
    |          ^^^^^^^^^ cannot borrow as mutable
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr
index ee2c831bfcc..31930e8c033 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr
@@ -1,136 +1,191 @@
-error: this pattern relies on behavior which may change in edition 2024
+error: binding modifiers may only be written when the default binding mode is `move`
   --> $DIR/ref-binding-on-inh-ref-errors.rs:15:11
    |
 LL |     let [&ref x] = &[&0];
-   |           ^^^ cannot override to bind by-reference when that is the implicit default
+   |           ^^^ binding modifier not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:15:9
+   |
+LL |     let [&ref x] = &[&0];
+   |         ^^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL |     let &[&ref x] = &[&0];
    |         +
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:21:11
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:20:11
    |
 LL |     let [&ref x] = &mut [&0];
-   |           ^^^ cannot override to bind by-reference when that is the implicit default
+   |           ^^^ binding modifier not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:20:9
+   |
+LL |     let [&ref x] = &mut [&0];
+   |         ^^^^^^^^ this matches on type `&mut _`
 help: make the implied reference pattern explicit
    |
 LL |     let &mut [&ref x] = &mut [&0];
    |         ++++
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:27:15
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:25:15
    |
 LL |     let [&mut ref x] = &mut [&mut 0];
-   |               ^^^ cannot override to bind by-reference when that is the implicit default
+   |               ^^^ binding modifier not allowed under `ref mut` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:25:9
+   |
+LL |     let [&mut ref x] = &mut [&mut 0];
+   |         ^^^^^^^^^^^^ this matches on type `&mut _`
 help: make the implied reference pattern explicit
    |
 LL |     let &mut [&mut ref x] = &mut [&mut 0];
    |         ++++
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:33:15
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:30:15
    |
 LL |     let [&mut ref mut x] = &mut [&mut 0];
-   |               ^^^^^^^ cannot override to bind by-reference when that is the implicit default
+   |               ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:30:9
+   |
+LL |     let [&mut ref mut x] = &mut [&mut 0];
+   |         ^^^^^^^^^^^^^^^^ this matches on type `&mut _`
 help: make the implied reference pattern explicit
    |
 LL |     let &mut [&mut ref mut x] = &mut [&mut 0];
    |         ++++
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:43:11
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:39:11
    |
 LL |     let [&ref x] = &[&mut 0];
-   |           ^^^ cannot override to bind by-reference when that is the implicit default
+   |           ^^^ binding modifier not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:39:9
+   |
+LL |     let [&ref x] = &[&mut 0];
+   |         ^^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL |     let &[&ref x] = &[&mut 0];
    |         +
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:50:11
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:45:11
    |
 LL |     let [&ref x] = &mut [&mut 0];
-   |           ^^^ cannot override to bind by-reference when that is the implicit default
+   |           ^^^ binding modifier not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:45:9
+   |
+LL |     let [&ref x] = &mut [&mut 0];
+   |         ^^^^^^^^ this matches on type `&mut _`
 help: make the implied reference pattern explicit
    |
 LL |     let &mut [&ref x] = &mut [&mut 0];
    |         ++++
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:60:15
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:54:15
    |
 LL |     let [&mut ref x] = &[&mut 0];
-   |               ^^^ cannot override to bind by-reference when that is the implicit default
+   |               ^^^ binding modifier not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:54:9
+   |
+LL |     let [&mut ref x] = &[&mut 0];
+   |         ^^^^^^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL |     let &[&mut ref x] = &[&mut 0];
    |         +
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:67:10
    |
 LL |     let [ref mut x] = &[0];
-   |          ^^^^^^^ cannot override to bind by-reference when that is the implicit default
+   |          ^^^^^^^ binding modifier not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:67:9
+   |
+LL |     let [ref mut x] = &[0];
+   |         ^^^^^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL |     let &[ref mut x] = &[0];
    |         +
 
 error[E0596]: cannot borrow data in a `&` reference as mutable
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:67:10
    |
 LL |     let [ref mut x] = &[0];
    |          ^^^^^^^^^ cannot borrow as mutable
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:83:10
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:75:10
    |
 LL |     let [ref x] = &[0];
-   |          ^^^ cannot override to bind by-reference when that is the implicit default
+   |          ^^^ binding modifier not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:75:9
+   |
+LL |     let [ref x] = &[0];
+   |         ^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL |     let &[ref x] = &[0];
    |         +
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:88:10
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:79:10
    |
 LL |     let [ref x] = &mut [0];
-   |          ^^^ cannot override to bind by-reference when that is the implicit default
+   |          ^^^ binding modifier not allowed under `ref mut` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:79:9
+   |
+LL |     let [ref x] = &mut [0];
+   |         ^^^^^^^ this matches on type `&mut _`
 help: make the implied reference pattern explicit
    |
 LL |     let &mut [ref x] = &mut [0];
    |         ++++
 
-error: this pattern relies on behavior which may change in edition 2024
-  --> $DIR/ref-binding-on-inh-ref-errors.rs:93:10
+error: binding modifiers may only be written when the default binding mode is `move`
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:83:10
    |
 LL |     let [ref mut x] = &mut [0];
-   |          ^^^^^^^ cannot override to bind by-reference when that is the implicit default
+   |          ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:83:9
+   |
+LL |     let [ref mut x] = &mut [0];
+   |         ^^^^^^^^^^^ this matches on type `&mut _`
 help: make the implied reference pattern explicit
    |
 LL |     let &mut [ref mut x] = &mut [0];
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed
index e2b2c987610..0a22e939496 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed
@@ -23,22 +23,22 @@ fn main() {
     assert_type_eq(x, &mut 0u8);
 
     let &Foo(mut x) = &Foo(0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, 0u8);
 
     let &mut Foo(mut x) = &mut Foo(0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, 0u8);
 
-    let &Foo(ref x) = &Foo(0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    let Foo(x) = &Foo(0);
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, &0u8);
 
     let &mut Foo(ref x) = &mut Foo(0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, &0u8);
 
@@ -55,22 +55,22 @@ fn main() {
     assert_type_eq(x, &0u8);
 
     let &Foo(&x) = &Foo(&0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, 0u8);
 
     let &Foo(&mut x) = &Foo(&mut 0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, 0u8);
 
     let &mut Foo(&x) = &mut Foo(&0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, 0u8);
 
     let &mut Foo(&mut x) = &mut Foo(&mut 0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, 0u8);
 
@@ -79,25 +79,25 @@ fn main() {
     }
 
     if let &&&&&Some(&x) = &&&&&Some(&0u8) {
-        //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+        //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
         //~| WARN: this changes meaning in Rust 2024
         assert_type_eq(x, 0u8);
     }
 
     if let &&&&&Some(&mut x) = &&&&&Some(&mut 0u8) {
-        //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+        //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
         //~| WARN: this changes meaning in Rust 2024
         assert_type_eq(x, 0u8);
     }
 
     if let &&&&&mut Some(&x) = &&&&&mut Some(&0u8) {
-        //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+        //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
         //~| WARN: this changes meaning in Rust 2024
         assert_type_eq(x, 0u8);
     }
 
     if let &mut Some(&mut Some(&mut Some(ref mut x))) = &mut Some(&mut Some(&mut Some(0u8))) {
-        //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+        //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
         //~| WARN: this changes meaning in Rust 2024
         assert_type_eq(x, &mut 0u8);
     }
@@ -109,20 +109,20 @@ fn main() {
     }
 
     let &Struct { ref a, mut b, ref c } = &Struct { a: 0, b: 0, c: 0 };
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(a, &0u32);
     assert_type_eq(b, 0u32);
 
     let &Struct { a: &a, ref b, ref c } = &Struct { a: &0, b: &0, c: &0 };
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: binding modifiers and reference patterns may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(a, 0u32);
     assert_type_eq(b, &&0u32);
     assert_type_eq(c, &&0u32);
 
     if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } =
-        //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+        //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
         //~| WARN: this changes meaning in Rust 2024
         &(Struct { a: &Some(&0), b: &Some(&0), c: &Some(&0) })
     {
@@ -135,10 +135,108 @@ fn main() {
         // The two patterns are the same syntactically, but because they're defined in different
         // editions they don't mean the same thing.
         &(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
-            //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+            //~^ ERROR: binding modifiers may only be written when the default binding mode is `move`
             assert_type_eq(x, 0u32);
             assert_type_eq(y, 0u32);
         }
         _ => {}
     }
+
+    let &mut [&mut &[ref a]] = &mut [&mut &[0]];
+    //~^ ERROR: binding modifiers and reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+
+    let &[&(_)] = &[&0];
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+
+    // NB: Most of the following tests are for possible future improvements to migration suggestions
+
+    // Test removing multiple binding modifiers.
+    let Struct { a, b, c } = &Struct { a: 0, b: 0, c: 0 };
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+    assert_type_eq(c, &0u32);
+
+    // Test that we don't change bindings' modes when removing binding modifiers.
+    let &mut Struct { ref a, ref mut b, ref mut c } = &mut Struct { a: 0, b: 0, c: 0 };
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+    assert_type_eq(b, &mut 0u32);
+    assert_type_eq(c, &mut 0u32);
+
+    // Test removing multiple reference patterns of various mutabilities, plus a binding modifier.
+    let &mut &Struct { a: &[ref a], b: &mut [&[ref b]], ref c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 };
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+    assert_type_eq(b, &0u32);
+    assert_type_eq(c, &0u32);
+
+    // Test that we don't change bindings' types when removing reference patterns.
+    let &Foo(&ref a) = &Foo(&0);
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+
+    // Test that we don't change bindings' modes when adding reference paterns (caught early).
+    let &(&a, ref b, &[ref c], &mut [&mut (ref d, &[ref e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]);
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, 0u32);
+    assert_type_eq(b, &0u32);
+    assert_type_eq(c, &0u32);
+    assert_type_eq(d, &0u32);
+    assert_type_eq(e, &0u32);
+
+    // Test that we don't change bindings' modes when adding reference patterns (caught late).
+    let &(ref a, &mut [ref b], &[mut c]) = &(0, &mut [0], &[0]);
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+    assert_type_eq(b, &0u32);
+    assert_type_eq(c, 0u32);
+
+    // Test featuring both additions and removals.
+    let &(&a, &mut (ref b, &[ref c])) = &(&0, &mut (0, &[0]));
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, 0u32);
+    assert_type_eq(b, &0u32);
+    assert_type_eq(c, &0u32);
+
+    // Test that bindings' subpatterns' modes are updated properly.
+    let &[mut a @ ref b] = &[0];
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, 0u32);
+    assert_type_eq(b, &0u32);
+
+    // Test that bindings' subpatterns' modes are checked properly.
+    let &[ref a @ mut b] = &[0];
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+    assert_type_eq(b, 0u32);
+
+    // Test that we respect bindings' subpatterns' types when rewriting `&ref x` to `x`.
+    let [&Foo(&ref a @ ref b), &Foo(&ref c @ d)] = [&Foo(&0); 2];
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+    assert_type_eq(b, &0u32);
+    assert_type_eq(c, &0u32);
+    assert_type_eq(d, 0u32);
+
+    // Test that we respect bindings' subpatterns' modes when rewriting `&ref x` to `x`.
+    let [&Foo(&ref a @ [ref b]), &Foo(&ref c @ [d])] = [&Foo(&[0]); 2];
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &[0u32]);
+    assert_type_eq(b, &0u32);
+    assert_type_eq(c, &[0u32]);
+    assert_type_eq(d, 0u32);
 }
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs
index 098540adfa2..7a6f2269d44 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs
@@ -23,22 +23,22 @@ fn main() {
     assert_type_eq(x, &mut 0u8);
 
     let Foo(mut x) = &Foo(0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, 0u8);
 
     let Foo(mut x) = &mut Foo(0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, 0u8);
 
     let Foo(ref x) = &Foo(0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, &0u8);
 
     let Foo(ref x) = &mut Foo(0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, &0u8);
 
@@ -55,22 +55,22 @@ fn main() {
     assert_type_eq(x, &0u8);
 
     let Foo(&x) = &Foo(&0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, 0u8);
 
     let Foo(&mut x) = &Foo(&mut 0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, 0u8);
 
     let Foo(&x) = &mut Foo(&0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, 0u8);
 
     let Foo(&mut x) = &mut Foo(&mut 0);
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(x, 0u8);
 
@@ -79,25 +79,25 @@ fn main() {
     }
 
     if let Some(&x) = &&&&&Some(&0u8) {
-        //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+        //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
         //~| WARN: this changes meaning in Rust 2024
         assert_type_eq(x, 0u8);
     }
 
     if let Some(&mut x) = &&&&&Some(&mut 0u8) {
-        //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+        //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
         //~| WARN: this changes meaning in Rust 2024
         assert_type_eq(x, 0u8);
     }
 
     if let Some(&x) = &&&&&mut Some(&0u8) {
-        //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+        //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
         //~| WARN: this changes meaning in Rust 2024
         assert_type_eq(x, 0u8);
     }
 
     if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) {
-        //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+        //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
         //~| WARN: this changes meaning in Rust 2024
         assert_type_eq(x, &mut 0u8);
     }
@@ -109,20 +109,20 @@ fn main() {
     }
 
     let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 };
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(a, &0u32);
     assert_type_eq(b, 0u32);
 
     let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 };
-    //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //~^ ERROR: binding modifiers and reference patterns may only be written when the default binding mode is `move` in Rust 2024
     //~| WARN: this changes meaning in Rust 2024
     assert_type_eq(a, 0u32);
     assert_type_eq(b, &&0u32);
     assert_type_eq(c, &&0u32);
 
     if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } =
-        //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+        //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
         //~| WARN: this changes meaning in Rust 2024
         &(Struct { a: &Some(&0), b: &Some(&0), c: &Some(&0) })
     {
@@ -135,10 +135,108 @@ fn main() {
         // The two patterns are the same syntactically, but because they're defined in different
         // editions they don't mean the same thing.
         (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
-            //~^ ERROR: this pattern relies on behavior which may change in edition 2024
+            //~^ ERROR: binding modifiers may only be written when the default binding mode is `move`
             assert_type_eq(x, 0u32);
             assert_type_eq(y, 0u32);
         }
         _ => {}
     }
+
+    let [&mut [ref a]] = &mut [&mut &[0]];
+    //~^ ERROR: binding modifiers and reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+
+    let [&(_)] = &[&0];
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+
+    // NB: Most of the following tests are for possible future improvements to migration suggestions
+
+    // Test removing multiple binding modifiers.
+    let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 };
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+    assert_type_eq(c, &0u32);
+
+    // Test that we don't change bindings' modes when removing binding modifiers.
+    let Struct { ref a, ref mut b, c } = &mut Struct { a: 0, b: 0, c: 0 };
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+    assert_type_eq(b, &mut 0u32);
+    assert_type_eq(c, &mut 0u32);
+
+    // Test removing multiple reference patterns of various mutabilities, plus a binding modifier.
+    let Struct { a: &[ref a], b: &mut [[b]], c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 };
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+    assert_type_eq(b, &0u32);
+    assert_type_eq(c, &0u32);
+
+    // Test that we don't change bindings' types when removing reference patterns.
+    let Foo(&ref a) = &Foo(&0);
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+
+    // Test that we don't change bindings' modes when adding reference paterns (caught early).
+    let (&a, b, [c], [(d, [e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]);
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, 0u32);
+    assert_type_eq(b, &0u32);
+    assert_type_eq(c, &0u32);
+    assert_type_eq(d, &0u32);
+    assert_type_eq(e, &0u32);
+
+    // Test that we don't change bindings' modes when adding reference patterns (caught late).
+    let (a, [b], [mut c]) = &(0, &mut [0], &[0]);
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+    assert_type_eq(b, &0u32);
+    assert_type_eq(c, 0u32);
+
+    // Test featuring both additions and removals.
+    let (&a, (b, &[ref c])) = &(&0, &mut (0, &[0]));
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, 0u32);
+    assert_type_eq(b, &0u32);
+    assert_type_eq(c, &0u32);
+
+    // Test that bindings' subpatterns' modes are updated properly.
+    let [mut a @ b] = &[0];
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, 0u32);
+    assert_type_eq(b, &0u32);
+
+    // Test that bindings' subpatterns' modes are checked properly.
+    let [a @ mut b] = &[0];
+    //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+    assert_type_eq(b, 0u32);
+
+    // Test that we respect bindings' subpatterns' types when rewriting `&ref x` to `x`.
+    let [Foo(&ref a @ ref b), Foo(&ref c @ d)] = [&Foo(&0); 2];
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &0u32);
+    assert_type_eq(b, &0u32);
+    assert_type_eq(c, &0u32);
+    assert_type_eq(d, 0u32);
+
+    // Test that we respect bindings' subpatterns' modes when rewriting `&ref x` to `x`.
+    let [Foo(&ref a @ [ref b]), Foo(&ref c @ [d])] = [&Foo(&[0]); 2];
+    //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    assert_type_eq(a, &[0u32]);
+    assert_type_eq(b, &0u32);
+    assert_type_eq(c, &[0u32]);
+    assert_type_eq(d, 0u32);
 }
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr
index 83346b9dd4a..191800df07a 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr
@@ -1,11 +1,16 @@
-error: this pattern relies on behavior which may change in edition 2024
+error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:25:13
    |
 LL |     let Foo(mut x) = &Foo(0);
-   |             ^^^ requires binding by-value, but the implicit default is by-reference
+   |             ^^^ binding modifier not allowed under `ref` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:25:9
+   |
+LL |     let Foo(mut x) = &Foo(0);
+   |         ^^^^^^^^^^ this matches on type `&_`
 note: the lint level is defined here
   --> $DIR/migration_lint.rs:7:9
    |
@@ -16,206 +21,546 @@ help: make the implied reference pattern explicit
 LL |     let &Foo(mut x) = &Foo(0);
    |         +
 
-error: this pattern relies on behavior which may change in edition 2024
+error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:30:13
    |
 LL |     let Foo(mut x) = &mut Foo(0);
-   |             ^^^ requires binding by-value, but the implicit default is by-reference
+   |             ^^^ binding modifier not allowed under `ref mut` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:30:9
+   |
+LL |     let Foo(mut x) = &mut Foo(0);
+   |         ^^^^^^^^^^ this matches on type `&mut _`
 help: make the implied reference pattern explicit
    |
 LL |     let &mut Foo(mut x) = &mut Foo(0);
    |         ++++
 
-error: this pattern relies on behavior which may change in edition 2024
+error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:35:13
    |
 LL |     let Foo(ref x) = &Foo(0);
-   |             ^^^ cannot override to bind by-reference when that is the implicit default
+   |             ^^^ binding modifier not allowed under `ref` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
-help: make the implied reference pattern explicit
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:35:9
+   |
+LL |     let Foo(ref x) = &Foo(0);
+   |         ^^^^^^^^^^ this matches on type `&_`
+help: remove the unnecessary binding modifier
+   |
+LL -     let Foo(ref x) = &Foo(0);
+LL +     let Foo(x) = &Foo(0);
    |
-LL |     let &Foo(ref x) = &Foo(0);
-   |         +
 
-error: this pattern relies on behavior which may change in edition 2024
+error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:40:13
    |
 LL |     let Foo(ref x) = &mut Foo(0);
-   |             ^^^ cannot override to bind by-reference when that is the implicit default
+   |             ^^^ binding modifier not allowed under `ref mut` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:40:9
+   |
+LL |     let Foo(ref x) = &mut Foo(0);
+   |         ^^^^^^^^^^ this matches on type `&mut _`
 help: make the implied reference pattern explicit
    |
 LL |     let &mut Foo(ref x) = &mut Foo(0);
    |         ++++
 
-error: this pattern relies on behavior which may change in edition 2024
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:57:13
    |
 LL |     let Foo(&x) = &Foo(&0);
-   |             ^ cannot implicitly match against multiple layers of reference
+   |             ^ reference pattern not allowed under `ref` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:57:9
+   |
+LL |     let Foo(&x) = &Foo(&0);
+   |         ^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL |     let &Foo(&x) = &Foo(&0);
    |         +
 
-error: this pattern relies on behavior which may change in edition 2024
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:62:13
    |
 LL |     let Foo(&mut x) = &Foo(&mut 0);
-   |             ^^^^ cannot implicitly match against multiple layers of reference
+   |             ^^^^ reference pattern not allowed under `ref` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:62:9
+   |
+LL |     let Foo(&mut x) = &Foo(&mut 0);
+   |         ^^^^^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL |     let &Foo(&mut x) = &Foo(&mut 0);
    |         +
 
-error: this pattern relies on behavior which may change in edition 2024
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:67:13
    |
 LL |     let Foo(&x) = &mut Foo(&0);
-   |             ^ cannot implicitly match against multiple layers of reference
+   |             ^ reference pattern not allowed under `ref mut` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:67:9
+   |
+LL |     let Foo(&x) = &mut Foo(&0);
+   |         ^^^^^^^ this matches on type `&mut _`
 help: make the implied reference pattern explicit
    |
 LL |     let &mut Foo(&x) = &mut Foo(&0);
    |         ++++
 
-error: this pattern relies on behavior which may change in edition 2024
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:72:13
    |
 LL |     let Foo(&mut x) = &mut Foo(&mut 0);
-   |             ^^^^ cannot implicitly match against multiple layers of reference
+   |             ^^^^ reference pattern not allowed under `ref mut` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:72:9
+   |
+LL |     let Foo(&mut x) = &mut Foo(&mut 0);
+   |         ^^^^^^^^^^^ this matches on type `&mut _`
 help: make the implied reference pattern explicit
    |
 LL |     let &mut Foo(&mut x) = &mut Foo(&mut 0);
    |         ++++
 
-error: this pattern relies on behavior which may change in edition 2024
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:81:17
    |
 LL |     if let Some(&x) = &&&&&Some(&0u8) {
-   |                 ^ cannot implicitly match against multiple layers of reference
+   |                 ^ reference pattern not allowed under `ref` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:81:12
+   |
+LL |     if let Some(&x) = &&&&&Some(&0u8) {
+   |            ^^^^^^^^ this matches on type `&_`
 help: make the implied reference patterns explicit
    |
 LL |     if let &&&&&Some(&x) = &&&&&Some(&0u8) {
    |            +++++
 
-error: this pattern relies on behavior which may change in edition 2024
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:87:17
    |
 LL |     if let Some(&mut x) = &&&&&Some(&mut 0u8) {
-   |                 ^^^^ cannot implicitly match against multiple layers of reference
+   |                 ^^^^ reference pattern not allowed under `ref` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:87:12
+   |
+LL |     if let Some(&mut x) = &&&&&Some(&mut 0u8) {
+   |            ^^^^^^^^^^^^ this matches on type `&_`
 help: make the implied reference patterns explicit
    |
 LL |     if let &&&&&Some(&mut x) = &&&&&Some(&mut 0u8) {
    |            +++++
 
-error: this pattern relies on behavior which may change in edition 2024
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:93:17
    |
 LL |     if let Some(&x) = &&&&&mut Some(&0u8) {
-   |                 ^ cannot implicitly match against multiple layers of reference
+   |                 ^ reference pattern not allowed under `ref` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:93:12
+   |
+LL |     if let Some(&x) = &&&&&mut Some(&0u8) {
+   |            ^^^^^^^^ this matches on type `&_`
 help: make the implied reference patterns explicit
    |
 LL |     if let &&&&&mut Some(&x) = &&&&&mut Some(&0u8) {
    |            ++++++++
 
-error: this pattern relies on behavior which may change in edition 2024
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:99:17
    |
 LL |     if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) {
-   |                 ^^^^ cannot implicitly match against multiple layers of reference
+   |                 ^^^^ reference pattern not allowed under `ref mut` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:99:12
+   |
+LL |     if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&mut _`
 help: make the implied reference patterns and variable binding mode explicit
    |
 LL |     if let &mut Some(&mut Some(&mut Some(ref mut x))) = &mut Some(&mut Some(&mut Some(0u8))) {
    |            ++++                ++++      +++++++
 
-error: this pattern relies on behavior which may change in edition 2024
+error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:111:21
    |
 LL |     let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 };
-   |                     ^^^ requires binding by-value, but the implicit default is by-reference
+   |                     ^^^ binding modifier not allowed under `ref` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:111:9
+   |
+LL |     let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 };
+   |         ^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern and variable binding modes explicit
    |
 LL |     let &Struct { ref a, mut b, ref c } = &Struct { a: 0, b: 0, c: 0 };
    |         +         +++           +++
 
-error: this pattern relies on behavior which may change in edition 2024
+error: binding modifiers and reference patterns may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:117:21
    |
 LL |     let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 };
-   |                     ^      ^^^ cannot override to bind by-reference when that is the implicit default
+   |                     ^      ^^^ binding modifier not allowed under `ref` default binding mode
    |                     |
-   |                     cannot implicitly match against multiple layers of reference
+   |                     reference pattern not allowed under `ref` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:117:9
+   |
+LL |     let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 };
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern and variable binding mode explicit
    |
 LL |     let &Struct { a: &a, ref b, ref c } = &Struct { a: &0, b: &0, c: &0 };
    |         +                +++
 
-error: this pattern relies on behavior which may change in edition 2024
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
   --> $DIR/migration_lint.rs:124:24
    |
 LL |     if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } =
-   |                        ^                 ^ cannot implicitly match against multiple layers of reference
+   |                        ^                 ^ reference pattern not allowed under `ref` default binding mode
    |                        |
-   |                        cannot implicitly match against multiple layers of reference
+   |                        reference pattern not allowed under `ref` default binding mode
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:124:12
+   |
+LL |     if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } =
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_`
 help: make the implied reference patterns and variable binding mode explicit
    |
 LL |     if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } =
    |            +                         +             +     +++
 
-error: this pattern relies on behavior which may change in edition 2024
+error: binding modifiers may only be written when the default binding mode is `move`
   --> $DIR/migration_lint.rs:137:15
    |
 LL |         (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
-   |               ^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ default binding mode is reset within expansion
+   |               ^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ occurs within macro expansion
    |               |
-   |               requires binding by-value, but the implicit default is by-reference
+   |               binding modifier not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:137:9
+   |
+LL |         (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_`
    = note: this error originates in the macro `migration_lint_macros::mixed_edition_pat` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: make the implied reference pattern explicit
    |
 LL |         &(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
    |         +
 
-error: aborting due to 16 previous errors
+error: binding modifiers and reference patterns may only be written when the default binding mode is `move` in Rust 2024
+  --> $DIR/migration_lint.rs:145:10
+   |
+LL |     let [&mut [ref a]] = &mut [&mut &[0]];
+   |          ^^^^  ^^^ binding modifier not allowed under `ref` default binding mode
+   |          |
+   |          reference pattern not allowed under `ref mut` default binding mode
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:145:15
+   |
+LL |     let [&mut [ref a]] = &mut [&mut &[0]];
+   |               ^^^^^^^ this matches on type `&_`
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:145:9
+   |
+LL |     let [&mut [ref a]] = &mut [&mut &[0]];
+   |         ^^^^^^^^^^^^^^ this matches on type `&mut _`
+help: make the implied reference patterns explicit
+   |
+LL |     let &mut [&mut &[ref a]] = &mut [&mut &[0]];
+   |         ++++       +
+
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+  --> $DIR/migration_lint.rs:150:10
+   |
+LL |     let [&(_)] = &[&0];
+   |          ^ reference pattern not allowed under `ref` default binding mode
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:150:9
+   |
+LL |     let [&(_)] = &[&0];
+   |         ^^^^^^ this matches on type `&_`
+help: make the implied reference pattern explicit
+   |
+LL |     let &[&(_)] = &[&0];
+   |         +
+
+error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+  --> $DIR/migration_lint.rs:157:18
+   |
+LL |     let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 };
+   |                  ^^^    ^^^ binding modifier not allowed under `ref` default binding mode
+   |                  |
+   |                  binding modifier not allowed under `ref` default binding mode
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:157:9
+   |
+LL |     let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 };
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_`
+help: remove the unnecessary binding modifiers
+   |
+LL -     let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 };
+LL +     let Struct { a, b, c } = &Struct { a: 0, b: 0, c: 0 };
+   |
+
+error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+  --> $DIR/migration_lint.rs:164:18
+   |
+LL |     let Struct { ref a, ref mut b, c } = &mut Struct { a: 0, b: 0, c: 0 };
+   |                  ^^^    ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode
+   |                  |
+   |                  binding modifier not allowed under `ref mut` default binding mode
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:164:9
+   |
+LL |     let Struct { ref a, ref mut b, c } = &mut Struct { a: 0, b: 0, c: 0 };
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&mut _`
+help: make the implied reference pattern and variable binding mode explicit
+   |
+LL |     let &mut Struct { ref a, ref mut b, ref mut c } = &mut Struct { a: 0, b: 0, c: 0 };
+   |         ++++                            +++++++
+
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+  --> $DIR/migration_lint.rs:172:21
+   |
+LL |     let Struct { a: &[ref a], b: &mut [[b]], c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 };
+   |                     ^            ^^^^ reference pattern not allowed under `ref` default binding mode
+   |                     |
+   |                     reference pattern not allowed under `ref` default binding mode
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:172:9
+   |
+LL |     let Struct { a: &[ref a], b: &mut [[b]], c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 };
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_`
+help: make the implied reference patterns and variable binding modes explicit
+   |
+LL |     let &mut &Struct { a: &[ref a], b: &mut [&[ref b]], ref c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 };
+   |         ++++++                               + +++      +++
+
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+  --> $DIR/migration_lint.rs:180:13
+   |
+LL |     let Foo(&ref a) = &Foo(&0);
+   |             ^ reference pattern not allowed under `ref` default binding mode
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:180:9
+   |
+LL |     let Foo(&ref a) = &Foo(&0);
+   |         ^^^^^^^^^^^ this matches on type `&_`
+help: make the implied reference pattern explicit
+   |
+LL |     let &Foo(&ref a) = &Foo(&0);
+   |         +
+
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+  --> $DIR/migration_lint.rs:186:10
+   |
+LL |     let (&a, b, [c], [(d, [e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]);
+   |          ^ reference pattern not allowed under `ref` default binding mode
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:186:9
+   |
+LL |     let (&a, b, [c], [(d, [e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_`
+help: make the implied reference patterns and variable binding modes explicit
+   |
+LL |     let &(&a, ref b, &[ref c], &mut [&mut (ref d, &[ref e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]);
+   |         +     +++    + +++     ++++  ++++  +++    + +++
+
+error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+  --> $DIR/migration_lint.rs:196:19
+   |
+LL |     let (a, [b], [mut c]) = &(0, &mut [0], &[0]);
+   |                   ^^^ binding modifier not allowed under `ref` default binding mode
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:196:9
+   |
+LL |     let (a, [b], [mut c]) = &(0, &mut [0], &[0]);
+   |         ^^^^^^^^^^^^^^^^^ this matches on type `&_`
+help: make the implied reference patterns and variable binding modes explicit
+   |
+LL |     let &(ref a, &mut [ref b], &[mut c]) = &(0, &mut [0], &[0]);
+   |         + +++    ++++  +++     +
+
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+  --> $DIR/migration_lint.rs:204:10
+   |
+LL |     let (&a, (b, &[ref c])) = &(&0, &mut (0, &[0]));
+   |          ^       ^ reference pattern not allowed under `ref` default binding mode
+   |          |
+   |          reference pattern not allowed under `ref` default binding mode
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:204:9
+   |
+LL |     let (&a, (b, &[ref c])) = &(&0, &mut (0, &[0]));
+   |         ^^^^^^^^^^^^^^^^^^^ this matches on type `&_`
+help: make the implied reference patterns and variable binding mode explicit
+   |
+LL |     let &(&a, &mut (ref b, &[ref c])) = &(&0, &mut (0, &[0]));
+   |         +     ++++  +++
+
+error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+  --> $DIR/migration_lint.rs:212:10
+   |
+LL |     let [mut a @ b] = &[0];
+   |          ^^^ binding modifier not allowed under `ref` default binding mode
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:212:9
+   |
+LL |     let [mut a @ b] = &[0];
+   |         ^^^^^^^^^^^ this matches on type `&_`
+help: make the implied reference pattern and variable binding mode explicit
+   |
+LL |     let &[mut a @ ref b] = &[0];
+   |         +         +++
+
+error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024
+  --> $DIR/migration_lint.rs:219:14
+   |
+LL |     let [a @ mut b] = &[0];
+   |              ^^^ binding modifier not allowed under `ref` default binding mode
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:219:9
+   |
+LL |     let [a @ mut b] = &[0];
+   |         ^^^^^^^^^^^ this matches on type `&_`
+help: make the implied reference pattern and variable binding mode explicit
+   |
+LL |     let &[ref a @ mut b] = &[0];
+   |         + +++
+
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+  --> $DIR/migration_lint.rs:226:14
+   |
+LL |     let [Foo(&ref a @ ref b), Foo(&ref c @ d)] = [&Foo(&0); 2];
+   |              ^                    ^ reference pattern not allowed under `ref` default binding mode
+   |              |
+   |              reference pattern not allowed under `ref` default binding mode
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:226:31
+   |
+LL |     let [Foo(&ref a @ ref b), Foo(&ref c @ d)] = [&Foo(&0); 2];
+   |                               ^^^^^^^^^^^^^^^ this matches on type `&_`
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:226:10
+   |
+LL |     let [Foo(&ref a @ ref b), Foo(&ref c @ d)] = [&Foo(&0); 2];
+   |          ^^^^^^^^^^^^^^^^^^^ this matches on type `&_`
+help: make the implied reference patterns explicit
+   |
+LL |     let [&Foo(&ref a @ ref b), &Foo(&ref c @ d)] = [&Foo(&0); 2];
+   |          +                     +
+
+error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
+  --> $DIR/migration_lint.rs:235:14
+   |
+LL |     let [Foo(&ref a @ [ref b]), Foo(&ref c @ [d])] = [&Foo(&[0]); 2];
+   |              ^                      ^ reference pattern not allowed under `ref` default binding mode
+   |              |
+   |              reference pattern not allowed under `ref` default binding mode
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:235:33
+   |
+LL |     let [Foo(&ref a @ [ref b]), Foo(&ref c @ [d])] = [&Foo(&[0]); 2];
+   |                                 ^^^^^^^^^^^^^^^^^ this matches on type `&_`
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/migration_lint.rs:235:10
+   |
+LL |     let [Foo(&ref a @ [ref b]), Foo(&ref c @ [d])] = [&Foo(&[0]); 2];
+   |          ^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_`
+help: make the implied reference patterns explicit
+   |
+LL |     let [&Foo(&ref a @ [ref b]), &Foo(&ref c @ [d])] = [&Foo(&[0]); 2];
+   |          +                       +
+
+error: aborting due to 29 previous errors
 
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs
index 5ba554fc6e5..4dc04d90aaf 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs
@@ -21,17 +21,17 @@ macro_rules! test_pat_on_type {
 }
 
 test_pat_on_type![(&x,): &(T,)]; //~ ERROR mismatched types
-test_pat_on_type![(&x,): &(&T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
+test_pat_on_type![(&x,): &(&T,)]; //~ ERROR reference patterns may only be written when the default binding mode is `move`
 test_pat_on_type![(&x,): &(&mut T,)]; //~ ERROR mismatched types
 test_pat_on_type![(&mut x,): &(&T,)]; //~ ERROR mismatched types
-test_pat_on_type![(&mut x,): &(&mut T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
+test_pat_on_type![(&mut x,): &(&mut T,)]; //~ ERROR reference patterns may only be written when the default binding mode is `move`
 test_pat_on_type![(&x,): &&mut &(T,)]; //~ ERROR mismatched types
 test_pat_on_type![Foo { f: (&x,) }: Foo]; //~ ERROR mismatched types
 test_pat_on_type![Foo { f: (&x,) }: &mut Foo]; //~ ERROR mismatched types
-test_pat_on_type![Foo { f: &(x,) }: &Foo]; //~ ERROR this pattern relies on behavior which may change in edition 2024
-test_pat_on_type![(mut x,): &(T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
-test_pat_on_type![(ref x,): &(T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
-test_pat_on_type![(ref mut x,): &mut (T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
+test_pat_on_type![Foo { f: &(x,) }: &Foo]; //~ ERROR reference patterns may only be written when the default binding mode is `move`
+test_pat_on_type![(mut x,): &(T,)]; //~ ERROR binding modifiers may only be written when the default binding mode is `move`
+test_pat_on_type![(ref x,): &(T,)]; //~ ERROR binding modifiers may only be written when the default binding mode is `move`
+test_pat_on_type![(ref mut x,): &mut (T,)]; //~ ERROR binding modifiers may only be written when the default binding mode is `move`
 
 fn get<X>() -> X {
     unimplemented!()
@@ -40,6 +40,6 @@ fn get<X>() -> X {
 // Make sure this works even when the underlying type is inferred. This test passes on rust stable.
 fn infer<X: Copy>() -> X {
     match &get() {
-        (&x,) => x, //~ ERROR this pattern relies on behavior which may change in edition 2024
+        (&x,) => x, //~ ERROR reference patterns may only be written when the default binding mode is `move`
     }
 }
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr
index affdca1d449..0c6b2ff3a2f 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr
@@ -99,85 +99,122 @@ LL - test_pat_on_type![Foo { f: (&x,) }: &mut Foo];
 LL + test_pat_on_type![Foo { f: (x,) }: &mut Foo];
    |
 
-error: this pattern relies on behavior which may change in edition 2024
+error: reference patterns may only be written when the default binding mode is `move`
   --> $DIR/min_match_ergonomics_fail.rs:24:20
    |
 LL | test_pat_on_type![(&x,): &(&T,)];
-   |                    ^ cannot implicitly match against multiple layers of reference
+   |                    ^ reference pattern not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/min_match_ergonomics_fail.rs:24:19
+   |
+LL | test_pat_on_type![(&x,): &(&T,)];
+   |                   ^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL | test_pat_on_type![&(&x,): &(&T,)];
    |                   +
 
-error: this pattern relies on behavior which may change in edition 2024
+error: reference patterns may only be written when the default binding mode is `move`
   --> $DIR/min_match_ergonomics_fail.rs:27:20
    |
 LL | test_pat_on_type![(&mut x,): &(&mut T,)];
-   |                    ^^^^ cannot implicitly match against multiple layers of reference
+   |                    ^^^^ reference pattern not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/min_match_ergonomics_fail.rs:27:19
+   |
+LL | test_pat_on_type![(&mut x,): &(&mut T,)];
+   |                   ^^^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL | test_pat_on_type![&(&mut x,): &(&mut T,)];
    |                   +
 
-error: this pattern relies on behavior which may change in edition 2024
+error: reference patterns may only be written when the default binding mode is `move`
   --> $DIR/min_match_ergonomics_fail.rs:31:28
    |
 LL | test_pat_on_type![Foo { f: &(x,) }: &Foo];
-   |                            ^ cannot implicitly match against multiple layers of reference
+   |                            ^ reference pattern not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/min_match_ergonomics_fail.rs:31:19
+   |
+LL | test_pat_on_type![Foo { f: &(x,) }: &Foo];
+   |                   ^^^^^^^^^^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL | test_pat_on_type![&Foo { f: &(x,) }: &Foo];
    |                   +
 
-error: this pattern relies on behavior which may change in edition 2024
+error: binding modifiers may only be written when the default binding mode is `move`
   --> $DIR/min_match_ergonomics_fail.rs:32:20
    |
 LL | test_pat_on_type![(mut x,): &(T,)];
-   |                    ^^^ requires binding by-value, but the implicit default is by-reference
+   |                    ^^^ binding modifier not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/min_match_ergonomics_fail.rs:32:19
+   |
+LL | test_pat_on_type![(mut x,): &(T,)];
+   |                   ^^^^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL | test_pat_on_type![&(mut x,): &(T,)];
    |                   +
 
-error: this pattern relies on behavior which may change in edition 2024
+error: binding modifiers may only be written when the default binding mode is `move`
   --> $DIR/min_match_ergonomics_fail.rs:33:20
    |
 LL | test_pat_on_type![(ref x,): &(T,)];
-   |                    ^^^ cannot override to bind by-reference when that is the implicit default
+   |                    ^^^ binding modifier not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
-help: make the implied reference pattern explicit
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/min_match_ergonomics_fail.rs:33:19
+   |
+LL | test_pat_on_type![(ref x,): &(T,)];
+   |                   ^^^^^^^^ this matches on type `&_`
+help: remove the unnecessary binding modifier
+   |
+LL - test_pat_on_type![(ref x,): &(T,)];
+LL + test_pat_on_type![(x,): &(T,)];
    |
-LL | test_pat_on_type![&(ref x,): &(T,)];
-   |                   +
 
-error: this pattern relies on behavior which may change in edition 2024
+error: binding modifiers may only be written when the default binding mode is `move`
   --> $DIR/min_match_ergonomics_fail.rs:34:20
    |
 LL | test_pat_on_type![(ref mut x,): &mut (T,)];
-   |                    ^^^^^^^ cannot override to bind by-reference when that is the implicit default
+   |                    ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
-help: make the implied reference pattern explicit
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/min_match_ergonomics_fail.rs:34:19
+   |
+LL | test_pat_on_type![(ref mut x,): &mut (T,)];
+   |                   ^^^^^^^^^^^^ this matches on type `&mut _`
+help: remove the unnecessary binding modifier
+   |
+LL - test_pat_on_type![(ref mut x,): &mut (T,)];
+LL + test_pat_on_type![(x,): &mut (T,)];
    |
-LL | test_pat_on_type![&mut (ref mut x,): &mut (T,)];
-   |                   ++++
 
-error: this pattern relies on behavior which may change in edition 2024
+error: reference patterns may only be written when the default binding mode is `move`
   --> $DIR/min_match_ergonomics_fail.rs:43:10
    |
 LL |         (&x,) => x,
-   |          ^ cannot implicitly match against multiple layers of reference
+   |          ^ reference pattern not allowed under `ref` default binding mode
    |
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+note: matching on a reference type with a non-reference pattern changes the default binding mode
+  --> $DIR/min_match_ergonomics_fail.rs:43:9
+   |
+LL |         (&x,) => x,
+   |         ^^^^^ this matches on type `&_`
 help: make the implied reference pattern explicit
    |
 LL |         &(&x,) => x,
diff --git a/tests/ui/process/win-creation-flags.rs b/tests/ui/process/win-creation-flags.rs
new file mode 100644
index 00000000000..0c7c6883d68
--- /dev/null
+++ b/tests/ui/process/win-creation-flags.rs
@@ -0,0 +1,51 @@
+// Test that windows `creation_flags` extension to `Command` works.
+
+//@ run-pass
+//@ only-windows
+//@ needs-subprocess
+
+use std::env;
+use std::os::windows::process::CommandExt;
+use std::process::{Command, exit};
+
+fn main() {
+    if env::args().skip(1).any(|s| s == "--child") {
+        child();
+    } else {
+        parent();
+    }
+}
+
+fn parent() {
+    let exe = env::current_exe().unwrap();
+
+    // Use the DETACH_PROCESS to create a subprocess that isn't attached to the console.
+    // The subprocess's exit status will be 0 if it's detached.
+    let status = Command::new(&exe)
+        .arg("--child")
+        .creation_flags(DETACH_PROCESS)
+        .spawn()
+        .unwrap()
+        .wait()
+        .unwrap();
+    assert_eq!(status.code(), Some(0));
+
+    // Try without DETACH_PROCESS to ensure this test works.
+    let status = Command::new(&exe).arg("--child").spawn().unwrap().wait().unwrap();
+    assert_eq!(status.code(), Some(1));
+}
+
+// exits with 1 if the console is attached or 0 otherwise
+fn child() {
+    // Get the attached console's code page.
+    // This will fail (return 0) if no console is attached.
+    let has_console = GetConsoleCP() != 0;
+    exit(has_console as i32);
+}
+
+// Windows API definitions.
+const DETACH_PROCESS: u32 = 0x00000008;
+#[link(name = "kernel32")]
+unsafe extern "system" {
+    safe fn GetConsoleCP() -> u32;
+}
diff --git a/tests/ui/process/win-proc-thread-attributes.rs b/tests/ui/process/win-proc-thread-attributes.rs
new file mode 100644
index 00000000000..91bb0b17e95
--- /dev/null
+++ b/tests/ui/process/win-proc-thread-attributes.rs
@@ -0,0 +1,118 @@
+// Tests proc thread attributes by spawning a process with a custom parent process,
+// then comparing the parent process ID with the expected parent process ID.
+
+//@ run-pass
+//@ only-windows
+//@ needs-subprocess
+//@ edition: 2021
+
+#![feature(windows_process_extensions_raw_attribute)]
+
+use std::os::windows::io::AsRawHandle;
+use std::os::windows::process::{CommandExt, ProcThreadAttributeList};
+use std::process::{Child, Command};
+use std::{env, mem, ptr, thread, time};
+
+// Make a best effort to ensure child processes always exit.
+struct ProcessDropGuard(Child);
+impl Drop for ProcessDropGuard {
+    fn drop(&mut self) {
+        let _ = self.0.kill();
+    }
+}
+
+fn main() {
+    if env::args().skip(1).any(|s| s == "--child") {
+        child();
+    } else {
+        parent();
+    }
+}
+
+fn parent() {
+    let exe = env::current_exe().unwrap();
+
+    let (fake_parent_id, child_parent_id) = {
+        // Create a process to be our fake parent process.
+        let fake_parent = Command::new(&exe).arg("--child").spawn().unwrap();
+        let fake_parent = ProcessDropGuard(fake_parent);
+        let parent_handle = fake_parent.0.as_raw_handle();
+
+        // Create another process with the parent process set to the fake.
+        let mut attribute_list = ProcThreadAttributeList::build()
+            .attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_handle)
+            .finish()
+            .unwrap();
+        let child =
+            Command::new(&exe).arg("--child").spawn_with_attributes(&mut attribute_list).unwrap();
+        let child = ProcessDropGuard(child);
+
+        // Return the fake's process id and the child's parent's id.
+        (process_info(&fake_parent.0).process_id(), process_info(&child.0).parent_id())
+    };
+
+    assert_eq!(fake_parent_id, child_parent_id);
+}
+
+// A process that stays running until killed.
+fn child() {
+    // Don't wait forever if something goes wrong.
+    thread::sleep(time::Duration::from_secs(60));
+}
+
+fn process_info(child: &Child) -> PROCESS_BASIC_INFORMATION {
+    unsafe {
+        let mut info: PROCESS_BASIC_INFORMATION = mem::zeroed();
+        let result = NtQueryInformationProcess(
+            child.as_raw_handle(),
+            ProcessBasicInformation,
+            ptr::from_mut(&mut info).cast(),
+            mem::size_of_val(&info).try_into().unwrap(),
+            ptr::null_mut(),
+        );
+        assert_eq!(result, 0);
+        info
+    }
+}
+
+// Windows API
+mod winapi {
+    #![allow(nonstandard_style)]
+    use std::ffi::c_void;
+
+    pub type HANDLE = *mut c_void;
+    type NTSTATUS = i32;
+    type PROCESSINFOCLASS = i32;
+
+    pub const ProcessBasicInformation: i32 = 0;
+    pub const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
+    #[repr(C)]
+    pub struct PROCESS_BASIC_INFORMATION {
+        pub ExitStatus: NTSTATUS,
+        pub PebBaseAddress: *mut (),
+        pub AffinityMask: usize,
+        pub BasePriority: i32,
+        pub UniqueProcessId: usize,
+        pub InheritedFromUniqueProcessId: usize,
+    }
+    impl PROCESS_BASIC_INFORMATION {
+        pub fn parent_id(&self) -> usize {
+            self.InheritedFromUniqueProcessId
+        }
+        pub fn process_id(&self) -> usize {
+            self.UniqueProcessId
+        }
+    }
+
+    #[link(name = "ntdll")]
+    extern "system" {
+        pub fn NtQueryInformationProcess(
+            ProcessHandle: HANDLE,
+            ProcessInformationClass: PROCESSINFOCLASS,
+            ProcessInformation: *mut c_void,
+            ProcessInformationLength: u32,
+            ReturnLength: *mut u32,
+        ) -> NTSTATUS;
+    }
+}
+use winapi::*;
diff --git a/tests/ui/sanitizer/cfi/supertraits.rs b/tests/ui/sanitizer/cfi/supertraits.rs
index 4bb6177577f..f80b3169188 100644
--- a/tests/ui/sanitizer/cfi/supertraits.rs
+++ b/tests/ui/sanitizer/cfi/supertraits.rs
@@ -1,4 +1,3 @@
-#![feature(trait_upcasting)]
 // Check that super-traits are callable.
 
 //@ revisions: cfi kcfi
diff --git a/tests/ui/self/arbitrary_self_types_dispatch_to_vtable.rs b/tests/ui/self/arbitrary_self_types_dispatch_to_vtable.rs
new file mode 100644
index 00000000000..f9e346ea11e
--- /dev/null
+++ b/tests/ui/self/arbitrary_self_types_dispatch_to_vtable.rs
@@ -0,0 +1,33 @@
+//@ check-pass
+
+#![feature(derive_coerce_pointee)]
+#![feature(arbitrary_self_types)]
+
+use std::marker::CoercePointee;
+use std::ops::Receiver;
+
+// `CoercePointee` isn't needed here, it's just a simpler
+// (and more conceptual) way of deriving `DispatchFromDyn`.
+// You could think of `MyDispatcher` as a smart pointer
+// that just doesn't deref to its target type.
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct MyDispatcher<T: ?Sized>(*const T);
+
+impl<T: ?Sized> Receiver for MyDispatcher<T> {
+    type Target = T;
+}
+struct Test;
+
+trait Trait {
+    fn test(self: MyDispatcher<Self>);
+}
+
+impl Trait for Test {
+    fn test(self: MyDispatcher<Self>) {
+        todo!()
+    }
+}
+fn main() {
+    MyDispatcher::<dyn Trait>(core::ptr::null_mut::<Test>()).test();
+}
diff --git a/tests/ui/structs-enums/class-impl-very-parameterized-trait.rs b/tests/ui/structs-enums/class-impl-very-parameterized-trait.rs
index 0b37192fc3b..6caec1e2034 100644
--- a/tests/ui/structs-enums/class-impl-very-parameterized-trait.rs
+++ b/tests/ui/structs-enums/class-impl-very-parameterized-trait.rs
@@ -102,6 +102,6 @@ pub fn main() {
     let mut spotty: cat<cat_type> = cat::new(2, 57, cat_type::tuxedo);
     for _ in 0_usize..6 { spotty.speak(); }
     assert_eq!(spotty.len(), 8);
-    assert!((spotty.contains_key(&2)));
+    assert!(spotty.contains_key(&2));
     assert_eq!(spotty.get(&3), &cat_type::tuxedo);
 }
diff --git a/tests/ui/structs-enums/class-implement-trait-cross-crate.rs b/tests/ui/structs-enums/class-implement-trait-cross-crate.rs
index 7a5969451cb..781ac6ad10d 100644
--- a/tests/ui/structs-enums/class-implement-trait-cross-crate.rs
+++ b/tests/ui/structs-enums/class-implement-trait-cross-crate.rs
@@ -53,7 +53,7 @@ fn cat(in_x : usize, in_y : isize, in_name: String) -> cat {
 pub fn main() {
   let mut nyan = cat(0_usize, 2, "nyan".to_string());
   nyan.eat();
-  assert!((!nyan.eat()));
+  assert!(!nyan.eat());
   for _ in 1_usize..10_usize { nyan.speak(); };
-  assert!((nyan.eat()));
+  assert!(nyan.eat());
 }
diff --git a/tests/ui/structs-enums/class-implement-traits.rs b/tests/ui/structs-enums/class-implement-traits.rs
index 04a7b706edb..3a514ff9d75 100644
--- a/tests/ui/structs-enums/class-implement-traits.rs
+++ b/tests/ui/structs-enums/class-implement-traits.rs
@@ -57,7 +57,7 @@ fn make_speak<C:noisy>(mut c: C) {
 pub fn main() {
     let mut nyan = cat(0_usize, 2, "nyan".to_string());
     nyan.eat();
-    assert!((!nyan.eat()));
+    assert!(!nyan.eat());
     for _ in 1_usize..10_usize {
         make_speak(nyan.clone());
     }
diff --git a/tests/ui/structs-enums/classes-cross-crate.rs b/tests/ui/structs-enums/classes-cross-crate.rs
index 0160d3fd85c..6fb5f2e3cc9 100644
--- a/tests/ui/structs-enums/classes-cross-crate.rs
+++ b/tests/ui/structs-enums/classes-cross-crate.rs
@@ -7,7 +7,7 @@ use cci_class_4::kitties::cat;
 pub fn main() {
     let mut nyan = cat(0_usize, 2, "nyan".to_string());
     nyan.eat();
-    assert!((!nyan.eat()));
+    assert!(!nyan.eat());
     for _ in 1_usize..10_usize { nyan.speak(); };
-    assert!((nyan.eat()));
+    assert!(nyan.eat());
 }
diff --git a/tests/ui/structs-enums/classes.rs b/tests/ui/structs-enums/classes.rs
index d1c1922f4b5..05976f6a759 100644
--- a/tests/ui/structs-enums/classes.rs
+++ b/tests/ui/structs-enums/classes.rs
@@ -45,7 +45,7 @@ fn cat(in_x : usize, in_y : isize, in_name: String) -> cat {
 pub fn main() {
   let mut nyan = cat(0_usize, 2, "nyan".to_string());
   nyan.eat();
-  assert!((!nyan.eat()));
+  assert!(!nyan.eat());
   for _ in 1_usize..10_usize { nyan.speak(); };
-  assert!((nyan.eat()));
+  assert!(nyan.eat());
 }
diff --git a/tests/ui/structs-enums/tag.rs b/tests/ui/structs-enums/tag.rs
index 16e6b2341cf..542b517e66d 100644
--- a/tests/ui/structs-enums/tag.rs
+++ b/tests/ui/structs-enums/tag.rs
@@ -25,6 +25,6 @@ impl PartialEq for colour {
     fn ne(&self, other: &colour) -> bool { !(*self).eq(other) }
 }
 
-fn f() { let x = colour::red(1, 2); let y = colour::green; assert!((x != y)); }
+fn f() { let x = colour::red(1, 2); let y = colour::green; assert!(x != y); }
 
 pub fn main() { f(); }
diff --git a/tests/ui/suggestions/suggest-null-ptr.stderr b/tests/ui/suggestions/suggest-null-ptr.stderr
index 66a79d0749e..a811d6d19c7 100644
--- a/tests/ui/suggestions/suggest-null-ptr.stderr
+++ b/tests/ui/suggestions/suggest-null-ptr.stderr
@@ -12,7 +12,7 @@ note: function defined here
   --> $DIR/suggest-null-ptr.rs:7:8
    |
 LL |     fn foo(ptr: *const u8);
-   |        ^^^
+   |        ^^^ ---
 help: if you meant to create a null pointer, use `std::ptr::null()`
    |
 LL |         foo(std::ptr::null());
@@ -32,7 +32,7 @@ note: function defined here
   --> $DIR/suggest-null-ptr.rs:9:8
    |
 LL |     fn foo_mut(ptr: *mut u8);
-   |        ^^^^^^^
+   |        ^^^^^^^ ---
 help: if you meant to create a null pointer, use `std::ptr::null_mut()`
    |
 LL |         foo_mut(std::ptr::null_mut());
@@ -52,7 +52,7 @@ note: function defined here
   --> $DIR/suggest-null-ptr.rs:11:8
    |
 LL |     fn usize(ptr: *const usize);
-   |        ^^^^^
+   |        ^^^^^ ---
 help: if you meant to create a null pointer, use `std::ptr::null()`
    |
 LL |         usize(std::ptr::null());
@@ -72,7 +72,7 @@ note: function defined here
   --> $DIR/suggest-null-ptr.rs:13:8
    |
 LL |     fn usize_mut(ptr: *mut usize);
-   |        ^^^^^^^^^
+   |        ^^^^^^^^^ ---
 help: if you meant to create a null pointer, use `std::ptr::null_mut()`
    |
 LL |         usize_mut(std::ptr::null_mut());
diff --git a/tests/ui/tail-cps.rs b/tests/ui/tail-cps.rs
index 6305e9ecdbc..fe99dadf795 100644
--- a/tests/ui/tail-cps.rs
+++ b/tests/ui/tail-cps.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 
-fn checktrue(rs: bool) -> bool { assert!((rs)); return true; }
+fn checktrue(rs: bool) -> bool { assert!(rs); return true; }
 
 pub fn main() { let k = checktrue; evenk(42, k); oddk(45, k); }
 
diff --git a/tests/ui/traits/next-solver/normalize/normalize-unsize-rhs.rs b/tests/ui/traits/next-solver/normalize/normalize-unsize-rhs.rs
index dc5912b123a..bbf9bafde9f 100644
--- a/tests/ui/traits/next-solver/normalize/normalize-unsize-rhs.rs
+++ b/tests/ui/traits/next-solver/normalize/normalize-unsize-rhs.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -Znext-solver
 //@ check-pass
-#![feature(trait_upcasting)]
 
 trait A {}
 trait B: A {}
diff --git a/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs b/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs
index ee6a7a0986d..c6094b45775 100644
--- a/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs
+++ b/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs
@@ -1,6 +1,5 @@
 //@ check-pass
 //@ compile-flags: -Znext-solver
-#![feature(trait_upcasting)]
 
 pub trait A {}
 pub trait B: A {}
diff --git a/tests/ui/traits/next-solver/upcast-right-substs.rs b/tests/ui/traits/next-solver/upcast-right-substs.rs
index bbb8a039aa7..7a566b59b83 100644
--- a/tests/ui/traits/next-solver/upcast-right-substs.rs
+++ b/tests/ui/traits/next-solver/upcast-right-substs.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -Znext-solver
 //@ check-pass
-#![feature(trait_upcasting)]
 
 trait Foo: Bar<i32> + Bar<u32> {}
 
diff --git a/tests/ui/traits/trait-upcasting/add-supertrait-auto-traits.rs b/tests/ui/traits/trait-upcasting/add-supertrait-auto-traits.rs
index ffc21a4a9ea..5b22fce6311 100644
--- a/tests/ui/traits/trait-upcasting/add-supertrait-auto-traits.rs
+++ b/tests/ui/traits/trait-upcasting/add-supertrait-auto-traits.rs
@@ -3,8 +3,6 @@
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
 
-#![feature(trait_upcasting)]
-
 trait Target {}
 trait Source: Send + Target {}
 
diff --git a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs
index 4a5e445d1ef..927a9d6b94f 100644
--- a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs
+++ b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs
@@ -1,4 +1,3 @@
-#![feature(trait_upcasting)]
 #![feature(trait_alias)]
 
 // Although we *elaborate* `T: Alias` to `i32: B`, we should
diff --git a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr
index 99c82b88d9c..1a410519a4e 100644
--- a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr
+++ b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/alias-where-clause-isnt-supertrait.rs:27:5
+  --> $DIR/alias-where-clause-isnt-supertrait.rs:26:5
    |
 LL | fn test(x: &dyn C) -> &dyn B {
    |                       ------ expected `&dyn B` because of return type
diff --git a/tests/ui/traits/trait-upcasting/basic.rs b/tests/ui/traits/trait-upcasting/basic.rs
index 9b9669565ba..0a8d16a42dd 100644
--- a/tests/ui/traits/trait-upcasting/basic.rs
+++ b/tests/ui/traits/trait-upcasting/basic.rs
@@ -1,7 +1,5 @@
 //@ run-pass
 
-#![feature(trait_upcasting)]
-
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     fn a(&self) -> i32 {
         10
diff --git a/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs b/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs
index 7f4343dbd2f..0a02784f29c 100644
--- a/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs
+++ b/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs
@@ -1,5 +1,4 @@
 //@ run-pass
-#![feature(trait_upcasting)]
 
 trait Foo<T: Default + ToString>: Bar<i32> + Bar<T> {}
 trait Bar<T: Default + ToString> {
diff --git a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs
deleted file mode 100644
index e4784fa4101..00000000000
--- a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-#![deny(deref_into_dyn_supertrait)]
-use std::ops::Deref;
-
-trait Bar<T> {}
-impl<T, U> Bar<U> for T {}
-
-trait Foo: Bar<i32> {
-    fn as_dyn_bar_u32<'a>(&self) -> &(dyn Bar<u32> + 'a);
-}
-
-impl Foo for () {
-    fn as_dyn_bar_u32<'a>(&self) -> &(dyn Bar<u32> + 'a) {
-        self
-    }
-}
-
-impl<'a> Deref for dyn Foo + 'a {
-    //~^ ERROR this `Deref` implementation is covered by an implicit supertrait coercion
-    //~| WARN this will change its meaning in a future release!
-    type Target = dyn Bar<u32> + 'a;
-
-    fn deref(&self) -> &Self::Target {
-        self.as_dyn_bar_u32()
-    }
-}
-
-fn take_dyn<T>(x: &dyn Bar<T>) -> T {
-    todo!()
-}
-
-fn main() {
-    let x: &dyn Foo = &();
-    let y = take_dyn(x);
-    let z: u32 = y;
-}
diff --git a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr
deleted file mode 100644
index fa93e28c73b..00000000000
--- a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error: this `Deref` implementation is covered by an implicit supertrait coercion
-  --> $DIR/deref-upcast-behavioral-change.rs:17:1
-   |
-LL | impl<'a> Deref for dyn Foo + 'a {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo` implements `Deref<Target = dyn Bar<u32>>` which conflicts with supertrait `Bar<i32>`
-...
-LL |     type Target = dyn Bar<u32> + 'a;
-   |     -------------------------------- target type is a supertrait of `dyn Foo`
-   |
-   = warning: this will change its meaning in a future release!
-   = note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
-note: the lint level is defined here
-  --> $DIR/deref-upcast-behavioral-change.rs:1:9
-   |
-LL | #![deny(deref_into_dyn_supertrait)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/traits/trait-upcasting/deref-upcast-shadowing-lint.rs b/tests/ui/traits/trait-upcasting/deref-upcast-shadowing-lint.rs
new file mode 100644
index 00000000000..ab84527edcf
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/deref-upcast-shadowing-lint.rs
@@ -0,0 +1,17 @@
+//@ check-pass
+#![warn(deref_into_dyn_supertrait)]
+use std::ops::Deref;
+
+trait Bar<T> {}
+trait Foo: Bar<i32> {}
+
+impl<'a> Deref for dyn Foo + 'a {
+    //~^ warn: this `Deref` implementation is covered by an implicit supertrait coercion
+    type Target = dyn Bar<u32> + 'a;
+
+    fn deref(&self) -> &Self::Target {
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/traits/trait-upcasting/deref-upcast-shadowing-lint.stderr b/tests/ui/traits/trait-upcasting/deref-upcast-shadowing-lint.stderr
new file mode 100644
index 00000000000..0d7f957a50e
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/deref-upcast-shadowing-lint.stderr
@@ -0,0 +1,17 @@
+warning: this `Deref` implementation is covered by an implicit supertrait coercion
+  --> $DIR/deref-upcast-shadowing-lint.rs:8:1
+   |
+LL | impl<'a> Deref for dyn Foo + 'a {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo` implements `Deref<Target = dyn Bar<u32>>` which conflicts with supertrait `Bar<i32>`
+LL |
+LL |     type Target = dyn Bar<u32> + 'a;
+   |     -------------------------------- target type is a supertrait of `dyn Foo`
+   |
+note: the lint level is defined here
+  --> $DIR/deref-upcast-shadowing-lint.rs:2:9
+   |
+LL | #![warn(deref_into_dyn_supertrait)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/trait-upcasting/diamond.rs b/tests/ui/traits/trait-upcasting/diamond.rs
index 303c99b67bd..c3f15a6d582 100644
--- a/tests/ui/traits/trait-upcasting/diamond.rs
+++ b/tests/ui/traits/trait-upcasting/diamond.rs
@@ -1,7 +1,5 @@
 //@ run-pass
 
-#![feature(trait_upcasting)]
-
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     fn a(&self) -> i32 {
         10
diff --git a/tests/ui/traits/trait-upcasting/fewer-associated.rs b/tests/ui/traits/trait-upcasting/fewer-associated.rs
index 45e8673b859..c2ea2a09d3a 100644
--- a/tests/ui/traits/trait-upcasting/fewer-associated.rs
+++ b/tests/ui/traits/trait-upcasting/fewer-associated.rs
@@ -4,8 +4,6 @@
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
 
-#![feature(trait_upcasting)]
-
 trait A: B {
     type Assoc;
 }
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
index c4c070e49fd..9f9bf21b5a9 100644
--- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
@@ -6,8 +6,6 @@
 // Check that we are able to instantiate a binder during trait upcasting,
 // and that it doesn't cause any issues with codegen either.
 
-#![feature(trait_upcasting)]
-
 trait Supertrait<'a, 'b> {}
 trait Subtrait<'a, 'b>: Supertrait<'a, 'b> {}
 
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs
index 2cf6fc75e77..af2594b95f3 100644
--- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs
@@ -5,7 +5,7 @@
 // We previously wrongly instantiated binders during trait upcasting,
 // allowing the super trait to be more generic than the sub trait.
 // This was unsound.
-#![feature(trait_upcasting)]
+
 trait Supertrait<'a, 'b> {
     fn cast(&self, x: &'a str) -> &'b str;
 }
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr
index 28be189ff1e..596380b0dbb 100644
--- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/illegal-upcast-from-impl.rs:17:66
+  --> $DIR/illegal-upcast-from-impl.rs:15:66
    |
 LL | fn illegal(x: &dyn Sub<Assoc = ()>) -> &dyn Super<Assoc = i32> { x }
    |                                        -----------------------   ^ expected trait `Super`, found trait `Sub`
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr
index 28be189ff1e..596380b0dbb 100644
--- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/illegal-upcast-from-impl.rs:17:66
+  --> $DIR/illegal-upcast-from-impl.rs:15:66
    |
 LL | fn illegal(x: &dyn Sub<Assoc = ()>) -> &dyn Super<Assoc = i32> { x }
    |                                        -----------------------   ^ expected trait `Super`, found trait `Sub`
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs
index 0c771db4121..43ec4ece429 100644
--- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs
@@ -2,8 +2,6 @@
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
 
-#![feature(trait_upcasting)]
-
 trait Super {
     type Assoc;
 }
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-to-impl-opaque.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-to-impl-opaque.rs
index d0418e75fab..2760c1696b5 100644
--- a/tests/ui/traits/trait-upcasting/illegal-upcast-to-impl-opaque.rs
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-to-impl-opaque.rs
@@ -9,8 +9,6 @@
 //@[next] rustc-env:RUST_BACKTRACE=0
 //@ check-pass
 
-#![feature(trait_upcasting)]
-
 trait Super {
     type Assoc;
 }
diff --git a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs
index 79fb643eacd..0103aaa2ac9 100644
--- a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs
+++ b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs
@@ -1,6 +1,3 @@
-#![deny(deref_into_dyn_supertrait)]
-#![feature(trait_upcasting)] // remove this and the test compiles
-
 use std::ops::Deref;
 
 trait Bar<T> {}
@@ -32,5 +29,5 @@ fn main() {
     let x: &dyn Foo = &();
     let y = take_dyn(x);
     let z: u32 = y;
-    //~^ ERROR mismatched types
+    //~^ error: mismatched types
 }
diff --git a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr
index 6b6a26d1593..45eabbc723a 100644
--- a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr
+++ b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/inference-behavior-change-deref.rs:34:18
+  --> $DIR/inference-behavior-change-deref.rs:31:18
    |
 LL |     let z: u32 = y;
    |            ---   ^ expected `u32`, found `i32`
diff --git a/tests/ui/traits/trait-upcasting/invalid-upcast.rs b/tests/ui/traits/trait-upcasting/invalid-upcast.rs
index e634bbd5ac6..9269a5e3e9f 100644
--- a/tests/ui/traits/trait-upcasting/invalid-upcast.rs
+++ b/tests/ui/traits/trait-upcasting/invalid-upcast.rs
@@ -1,5 +1,3 @@
-#![feature(trait_upcasting)]
-
 trait Foo {
     fn a(&self) -> i32 {
         10
diff --git a/tests/ui/traits/trait-upcasting/invalid-upcast.stderr b/tests/ui/traits/trait-upcasting/invalid-upcast.stderr
index 3aa21ee3ddd..e70b99d28c7 100644
--- a/tests/ui/traits/trait-upcasting/invalid-upcast.stderr
+++ b/tests/ui/traits/trait-upcasting/invalid-upcast.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:53:35
+  --> $DIR/invalid-upcast.rs:51:35
    |
 LL |     let _: &dyn std::fmt::Debug = baz;
    |            --------------------   ^^^ expected trait `Debug`, found trait `Baz`
@@ -10,7 +10,7 @@ LL |     let _: &dyn std::fmt::Debug = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:55:24
+  --> $DIR/invalid-upcast.rs:53:24
    |
 LL |     let _: &dyn Send = baz;
    |            ---------   ^^^ expected trait `Send`, found trait `Baz`
@@ -21,7 +21,7 @@ LL |     let _: &dyn Send = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:57:24
+  --> $DIR/invalid-upcast.rs:55:24
    |
 LL |     let _: &dyn Sync = baz;
    |            ---------   ^^^ expected trait `Sync`, found trait `Baz`
@@ -32,7 +32,7 @@ LL |     let _: &dyn Sync = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:60:25
+  --> $DIR/invalid-upcast.rs:58:25
    |
 LL |     let bar: &dyn Bar = baz;
    |              --------   ^^^ expected trait `Bar`, found trait `Baz`
@@ -43,7 +43,7 @@ LL |     let bar: &dyn Bar = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:62:35
+  --> $DIR/invalid-upcast.rs:60:35
    |
 LL |     let _: &dyn std::fmt::Debug = bar;
    |            --------------------   ^^^ expected trait `Debug`, found trait `Bar`
@@ -54,7 +54,7 @@ LL |     let _: &dyn std::fmt::Debug = bar;
               found reference `&dyn Bar`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:64:24
+  --> $DIR/invalid-upcast.rs:62:24
    |
 LL |     let _: &dyn Send = bar;
    |            ---------   ^^^ expected trait `Send`, found trait `Bar`
@@ -65,7 +65,7 @@ LL |     let _: &dyn Send = bar;
               found reference `&dyn Bar`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:66:24
+  --> $DIR/invalid-upcast.rs:64:24
    |
 LL |     let _: &dyn Sync = bar;
    |            ---------   ^^^ expected trait `Sync`, found trait `Bar`
@@ -76,7 +76,7 @@ LL |     let _: &dyn Sync = bar;
               found reference `&dyn Bar`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:69:25
+  --> $DIR/invalid-upcast.rs:67:25
    |
 LL |     let foo: &dyn Foo = baz;
    |              --------   ^^^ expected trait `Foo`, found trait `Baz`
@@ -87,7 +87,7 @@ LL |     let foo: &dyn Foo = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:71:35
+  --> $DIR/invalid-upcast.rs:69:35
    |
 LL |     let _: &dyn std::fmt::Debug = foo;
    |            --------------------   ^^^ expected trait `Debug`, found trait `Foo`
@@ -98,7 +98,7 @@ LL |     let _: &dyn std::fmt::Debug = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:73:24
+  --> $DIR/invalid-upcast.rs:71:24
    |
 LL |     let _: &dyn Send = foo;
    |            ---------   ^^^ expected trait `Send`, found trait `Foo`
@@ -109,7 +109,7 @@ LL |     let _: &dyn Send = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:75:24
+  --> $DIR/invalid-upcast.rs:73:24
    |
 LL |     let _: &dyn Sync = foo;
    |            ---------   ^^^ expected trait `Sync`, found trait `Foo`
@@ -120,7 +120,7 @@ LL |     let _: &dyn Sync = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:78:25
+  --> $DIR/invalid-upcast.rs:76:25
    |
 LL |     let foo: &dyn Foo = bar;
    |              --------   ^^^ expected trait `Foo`, found trait `Bar`
@@ -131,7 +131,7 @@ LL |     let foo: &dyn Foo = bar;
               found reference `&dyn Bar`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:80:35
+  --> $DIR/invalid-upcast.rs:78:35
    |
 LL |     let _: &dyn std::fmt::Debug = foo;
    |            --------------------   ^^^ expected trait `Debug`, found trait `Foo`
@@ -142,7 +142,7 @@ LL |     let _: &dyn std::fmt::Debug = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:82:24
+  --> $DIR/invalid-upcast.rs:80:24
    |
 LL |     let _: &dyn Send = foo;
    |            ---------   ^^^ expected trait `Send`, found trait `Foo`
@@ -153,7 +153,7 @@ LL |     let _: &dyn Send = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:84:24
+  --> $DIR/invalid-upcast.rs:82:24
    |
 LL |     let _: &dyn Sync = foo;
    |            ---------   ^^^ expected trait `Sync`, found trait `Foo`
diff --git a/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs b/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs
index ef3d366c381..8bf32efbe2e 100644
--- a/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs
+++ b/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs
@@ -1,5 +1,4 @@
 //@ run-pass
-#![feature(trait_upcasting)]
 
 struct Test {
     func: Box<dyn FnMut() + 'static>,
diff --git a/tests/ui/traits/trait-upcasting/issue-11515.current.stderr b/tests/ui/traits/trait-upcasting/issue-11515.current.stderr
deleted file mode 100644
index 8ce7d46012f..00000000000
--- a/tests/ui/traits/trait-upcasting/issue-11515.current.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0658]: cannot cast `dyn Fn()` to `dyn FnMut()`, trait upcasting coercion is experimental
-  --> $DIR/issue-11515.rs:11:38
-   |
-LL |     let test = Box::new(Test { func: closure });
-   |                                      ^^^^^^^
-   |
-   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
-   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = note: required when coercing `Box<(dyn Fn() + 'static)>` into `Box<(dyn FnMut() + 'static)>`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/trait-upcasting/issue-11515.next.stderr b/tests/ui/traits/trait-upcasting/issue-11515.next.stderr
deleted file mode 100644
index 8ce7d46012f..00000000000
--- a/tests/ui/traits/trait-upcasting/issue-11515.next.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0658]: cannot cast `dyn Fn()` to `dyn FnMut()`, trait upcasting coercion is experimental
-  --> $DIR/issue-11515.rs:11:38
-   |
-LL |     let test = Box::new(Test { func: closure });
-   |                                      ^^^^^^^
-   |
-   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
-   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = note: required when coercing `Box<(dyn Fn() + 'static)>` into `Box<(dyn FnMut() + 'static)>`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/trait-upcasting/issue-11515.rs b/tests/ui/traits/trait-upcasting/issue-11515.rs
index d251e804c3e..3b1f0a19cb9 100644
--- a/tests/ui/traits/trait-upcasting/issue-11515.rs
+++ b/tests/ui/traits/trait-upcasting/issue-11515.rs
@@ -1,3 +1,4 @@
+//@ check-pass
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
@@ -8,5 +9,5 @@ struct Test {
 
 fn main() {
     let closure: Box<dyn Fn() + 'static> = Box::new(|| ());
-    let test = Box::new(Test { func: closure }); //~ ERROR trait upcasting coercion is experimental [E0658]
+    let test = Box::new(Test { func: closure });
 }
diff --git a/tests/ui/traits/trait-upcasting/lifetime.rs b/tests/ui/traits/trait-upcasting/lifetime.rs
index ab006f8bedc..a3cbfd777a0 100644
--- a/tests/ui/traits/trait-upcasting/lifetime.rs
+++ b/tests/ui/traits/trait-upcasting/lifetime.rs
@@ -1,7 +1,5 @@
 //@ run-pass
 
-#![feature(trait_upcasting)]
-
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     fn a(&self) -> i32 {
         10
diff --git a/tests/ui/traits/trait-upcasting/lifetime.stderr b/tests/ui/traits/trait-upcasting/lifetime.stderr
index ca8f9cf63f3..589e9816d5a 100644
--- a/tests/ui/traits/trait-upcasting/lifetime.stderr
+++ b/tests/ui/traits/trait-upcasting/lifetime.stderr
@@ -1,5 +1,5 @@
 warning: methods `z` and `y` are never used
-  --> $DIR/lifetime.rs:10:8
+  --> $DIR/lifetime.rs:8:8
    |
 LL | trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
    |       --- methods in this trait
@@ -13,7 +13,7 @@ LL |     fn y(&self) -> i32 {
    = note: `#[warn(dead_code)]` on by default
 
 warning: method `w` is never used
-  --> $DIR/lifetime.rs:24:8
+  --> $DIR/lifetime.rs:22:8
    |
 LL | trait Bar: Foo {
    |       --- method in this trait
diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs
index da1a9cc2775..d33d3bfd5dc 100644
--- a/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs
+++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs
@@ -1,4 +1,5 @@
-#![deny(deref_into_dyn_supertrait)]
+//@ check-pass
+#![warn(deref_into_dyn_supertrait)]
 
 use std::ops::Deref;
 
@@ -6,8 +7,7 @@ trait Bar<'a> {}
 trait Foo<'a>: Bar<'a> {}
 
 impl<'a> Deref for dyn Foo<'a> {
-    //~^ ERROR this `Deref` implementation is covered by an implicit supertrait coercion
-    //~| WARN this will change its meaning in a future release!
+    //~^ warn: this `Deref` implementation is covered by an implicit supertrait coercion
     type Target = dyn Bar<'a>;
 
     fn deref(&self) -> &Self::Target {
diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr
index a5f3660d4bc..806c57e44a2 100644
--- a/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr
+++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr
@@ -1,19 +1,17 @@
-error: this `Deref` implementation is covered by an implicit supertrait coercion
-  --> $DIR/migrate-lint-deny-regions.rs:8:1
+warning: this `Deref` implementation is covered by an implicit supertrait coercion
+  --> $DIR/migrate-lint-deny-regions.rs:9:1
    |
 LL | impl<'a> Deref for dyn Foo<'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo<'_>` implements `Deref<Target = dyn Bar<'_>>` which conflicts with supertrait `Bar<'_>`
-...
+LL |
 LL |     type Target = dyn Bar<'a>;
    |     -------------------------- target type is a supertrait of `dyn Foo<'_>`
    |
-   = warning: this will change its meaning in a future release!
-   = note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
 note: the lint level is defined here
-  --> $DIR/migrate-lint-deny-regions.rs:1:9
+  --> $DIR/migrate-lint-deny-regions.rs:2:9
    |
-LL | #![deny(deref_into_dyn_supertrait)]
+LL | #![warn(deref_into_dyn_supertrait)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 1 previous error
+warning: 1 warning emitted
 
diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-deny.rs b/tests/ui/traits/trait-upcasting/migrate-lint-deny.rs
deleted file mode 100644
index 926b3649e01..00000000000
--- a/tests/ui/traits/trait-upcasting/migrate-lint-deny.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-#![deny(deref_into_dyn_supertrait)]
-
-use std::ops::Deref;
-
-// issue 89190
-trait A {}
-trait B: A {}
-
-impl<'a> Deref for dyn 'a + B {
-    //~^ ERROR this `Deref` implementation is covered by an implicit supertrait coercion
-    //~| WARN this will change its meaning in a future release!
-
-    type Target = dyn A;
-    fn deref(&self) -> &Self::Target {
-        todo!()
-    }
-}
-
-fn take_a(_: &dyn A) {}
-
-fn whoops(b: &dyn B) {
-    take_a(b)
-}
-
-fn main() {}
diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr b/tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr
deleted file mode 100644
index 29997a9b3d9..00000000000
--- a/tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error: this `Deref` implementation is covered by an implicit supertrait coercion
-  --> $DIR/migrate-lint-deny.rs:9:1
-   |
-LL | impl<'a> Deref for dyn 'a + B {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn B` implements `Deref<Target = dyn A>` which conflicts with supertrait `A`
-...
-LL |     type Target = dyn A;
-   |     -------------------- target type is a supertrait of `dyn B`
-   |
-   = warning: this will change its meaning in a future release!
-   = note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
-note: the lint level is defined here
-  --> $DIR/migrate-lint-deny.rs:1:9
-   |
-LL | #![deny(deref_into_dyn_supertrait)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs
index 8e62c4b95b0..20806f22886 100644
--- a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs
+++ b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs
@@ -1,4 +1,5 @@
 //@ check-pass
+#![warn(deref_into_dyn_supertrait)]
 
 use std::ops::Deref;
 
@@ -9,8 +10,7 @@ trait Foo: Bar<i32> {
 }
 
 impl<'a> Deref for dyn Foo + 'a {
-    //~^ WARN this `Deref` implementation is covered by an implicit supertrait coercion
-    //~| WARN this will change its meaning in a future release!
+    //~^ warn: this `Deref` implementation is covered by an implicit supertrait coercion
     type Target = dyn Bar<u32> + 'a;
 
     fn deref(&self) -> &Self::Target {
diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr
index 6245da5a176..86cff5233ff 100644
--- a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr
+++ b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr
@@ -1,15 +1,17 @@
 warning: this `Deref` implementation is covered by an implicit supertrait coercion
-  --> $DIR/migrate-lint-different-substs.rs:11:1
+  --> $DIR/migrate-lint-different-substs.rs:12:1
    |
 LL | impl<'a> Deref for dyn Foo + 'a {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo` implements `Deref<Target = dyn Bar<u32>>` which conflicts with supertrait `Bar<i32>`
-...
+LL |
 LL |     type Target = dyn Bar<u32> + 'a;
    |     -------------------------------- target type is a supertrait of `dyn Foo`
    |
-   = warning: this will change its meaning in a future release!
-   = note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
-   = note: `#[warn(deref_into_dyn_supertrait)]` on by default
+note: the lint level is defined here
+  --> $DIR/migrate-lint-different-substs.rs:2:9
+   |
+LL | #![warn(deref_into_dyn_supertrait)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/traits/trait-upcasting/mono-impossible.rs b/tests/ui/traits/trait-upcasting/mono-impossible.rs
index 88f19e1c95f..f19f0538efa 100644
--- a/tests/ui/traits/trait-upcasting/mono-impossible.rs
+++ b/tests/ui/traits/trait-upcasting/mono-impossible.rs
@@ -1,7 +1,5 @@
 //@ build-pass
 
-#![feature(trait_upcasting)]
-
 trait Supertrait<T> {
     fn method(&self) {}
 }
diff --git a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs
index 754437a3bec..0bf0d14c259 100644
--- a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs
+++ b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs
@@ -1,5 +1,4 @@
 //@ check-fail
-#![feature(trait_upcasting)]
 
 trait Bar<T> {
     fn bar(&self, _: T) {}
diff --git a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr
index 70ba1fcaf38..c888ccc1ebb 100644
--- a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr
+++ b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/multiple-occurrence-ambiguousity.rs:20:26
+  --> $DIR/multiple-occurrence-ambiguousity.rs:19:26
    |
 LL |     let t: &dyn Bar<_> = s;
    |            -----------   ^ expected trait `Bar`, found trait `Foo`
diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs
index 510a1471af2..a0bb1c57adb 100644
--- a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs
+++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs
@@ -1,10 +1,8 @@
+// Test for <https://github.com/rust-lang/rust/issues/135316>.
+//
 //@ run-pass
 //@ check-run-results
 
-// Test for <https://github.com/rust-lang/rust/issues/135316>.
-
-#![feature(trait_upcasting)]
-
 trait Supertrait<T> {
     fn _print_numbers(&self, mem: &[usize; 100]) {
         println!("{mem:?}");
diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.rs b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.rs
index 69a71859a5c..6b9ddf9bedc 100644
--- a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.rs
+++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.rs
@@ -1,5 +1,4 @@
 #![feature(rustc_attrs)]
-#![feature(trait_upcasting)]
 
 // Test for <https://github.com/rust-lang/rust/issues/135315>.
 
diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.stderr b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.stderr
index 757e2dc6939..04b1afae7be 100644
--- a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.stderr
+++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.stderr
@@ -5,7 +5,7 @@ error: vtable entries: [
            Method(<() as Supertrait<()>>::_print_numbers),
            Method(<() as Middle<()>>::say_hello),
        ]
-  --> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:30:1
+  --> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:29:1
    |
 LL | impl Trait for () {}
    | ^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ error: vtable entries: [
            Method(<dyn Middle<()> as Supertrait<()>>::_print_numbers - shim(reify)),
            Method(<dyn Middle<()> as Middle<()>>::say_hello - shim(reify)),
        ]
-  --> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:34:1
+  --> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:33:1
    |
 LL | type Virtual = dyn Middle<()>;
    | ^^^^^^^^^^^^
diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.rs b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.rs
index c744e6e64f5..08ec49971ac 100644
--- a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.rs
+++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.rs
@@ -1,10 +1,8 @@
+// Test for <https://github.com/rust-lang/rust/issues/135315>.
+//
 //@ run-pass
 //@ check-run-results
 
-#![feature(trait_upcasting)]
-
-// Test for <https://github.com/rust-lang/rust/issues/135315>.
-
 trait Supertrait<T> {
     fn _print_numbers(&self, mem: &[usize; 100]) {
         println!("{mem:?}");
diff --git a/tests/ui/traits/trait-upcasting/normalization.rs b/tests/ui/traits/trait-upcasting/normalization.rs
index ae5a6a5243c..b714479961f 100644
--- a/tests/ui/traits/trait-upcasting/normalization.rs
+++ b/tests/ui/traits/trait-upcasting/normalization.rs
@@ -4,8 +4,6 @@
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
 
-#![feature(trait_upcasting)]
-
 trait Mirror {
     type Assoc;
 }
diff --git a/tests/ui/traits/trait-upcasting/prefer-lower-candidates.rs b/tests/ui/traits/trait-upcasting/prefer-lower-candidates.rs
index 4bc59b09fb5..09557ba0260 100644
--- a/tests/ui/traits/trait-upcasting/prefer-lower-candidates.rs
+++ b/tests/ui/traits/trait-upcasting/prefer-lower-candidates.rs
@@ -6,8 +6,6 @@
 // Ensure we don't have ambiguity when upcasting to two supertraits
 // that are identical modulo normalization.
 
-#![feature(trait_upcasting)]
-
 trait Supertrait<T> {
     fn method(&self) {}
 }
diff --git a/tests/ui/traits/trait-upcasting/replace-vptr.rs b/tests/ui/traits/trait-upcasting/replace-vptr.rs
index 4829e3c5c12..6ca5864669b 100644
--- a/tests/ui/traits/trait-upcasting/replace-vptr.rs
+++ b/tests/ui/traits/trait-upcasting/replace-vptr.rs
@@ -1,7 +1,5 @@
 //@ run-pass
 
-#![feature(trait_upcasting)]
-
 trait A {
     fn foo_a(&self); //~ WARN method `foo_a` is never used
 }
diff --git a/tests/ui/traits/trait-upcasting/replace-vptr.stderr b/tests/ui/traits/trait-upcasting/replace-vptr.stderr
index 823094761b3..1a8bfd1bfa6 100644
--- a/tests/ui/traits/trait-upcasting/replace-vptr.stderr
+++ b/tests/ui/traits/trait-upcasting/replace-vptr.stderr
@@ -1,5 +1,5 @@
 warning: method `foo_a` is never used
-  --> $DIR/replace-vptr.rs:6:8
+  --> $DIR/replace-vptr.rs:4:8
    |
 LL | trait A {
    |       - method in this trait
@@ -9,7 +9,7 @@ LL |     fn foo_a(&self);
    = note: `#[warn(dead_code)]` on by default
 
 warning: method `foo_c` is never used
-  --> $DIR/replace-vptr.rs:14:8
+  --> $DIR/replace-vptr.rs:12:8
    |
 LL | trait C: A + B {
    |       - method in this trait
diff --git a/tests/ui/traits/trait-upcasting/struct.rs b/tests/ui/traits/trait-upcasting/struct.rs
index 39da20259a0..51e6f006fbf 100644
--- a/tests/ui/traits/trait-upcasting/struct.rs
+++ b/tests/ui/traits/trait-upcasting/struct.rs
@@ -1,7 +1,5 @@
 //@ run-pass
 
-#![feature(trait_upcasting)]
-
 use std::rc::Rc;
 use std::sync::Arc;
 
diff --git a/tests/ui/traits/trait-upcasting/subtrait-method.rs b/tests/ui/traits/trait-upcasting/subtrait-method.rs
index 136d15af0e8..20277280440 100644
--- a/tests/ui/traits/trait-upcasting/subtrait-method.rs
+++ b/tests/ui/traits/trait-upcasting/subtrait-method.rs
@@ -1,5 +1,3 @@
-#![feature(trait_upcasting)]
-
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     fn a(&self) -> i32 {
         10
diff --git a/tests/ui/traits/trait-upcasting/subtrait-method.stderr b/tests/ui/traits/trait-upcasting/subtrait-method.stderr
index 0408be6986b..a7658a7bcd3 100644
--- a/tests/ui/traits/trait-upcasting/subtrait-method.stderr
+++ b/tests/ui/traits/trait-upcasting/subtrait-method.stderr
@@ -1,12 +1,12 @@
 error[E0599]: no method named `c` found for reference `&dyn Bar` in the current scope
-  --> $DIR/subtrait-method.rs:55:9
+  --> $DIR/subtrait-method.rs:53:9
    |
 LL |     bar.c();
    |         ^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Baz` defines an item `c`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:27:1
+  --> $DIR/subtrait-method.rs:25:1
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
@@ -16,14 +16,14 @@ LL |     bar.a();
    |         ~
 
 error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope
-  --> $DIR/subtrait-method.rs:59:9
+  --> $DIR/subtrait-method.rs:57:9
    |
 LL |     foo.b();
    |         ^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Bar` defines an item `b`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:17:1
+  --> $DIR/subtrait-method.rs:15:1
    |
 LL | trait Bar: Foo {
    | ^^^^^^^^^^^^^^
@@ -33,14 +33,14 @@ LL |     foo.a();
    |         ~
 
 error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope
-  --> $DIR/subtrait-method.rs:61:9
+  --> $DIR/subtrait-method.rs:59:9
    |
 LL |     foo.c();
    |         ^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Baz` defines an item `c`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:27:1
+  --> $DIR/subtrait-method.rs:25:1
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
@@ -50,14 +50,14 @@ LL |     foo.a();
    |         ~
 
 error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope
-  --> $DIR/subtrait-method.rs:65:9
+  --> $DIR/subtrait-method.rs:63:9
    |
 LL |     foo.b();
    |         ^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Bar` defines an item `b`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:17:1
+  --> $DIR/subtrait-method.rs:15:1
    |
 LL | trait Bar: Foo {
    | ^^^^^^^^^^^^^^
@@ -67,14 +67,14 @@ LL |     foo.a();
    |         ~
 
 error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope
-  --> $DIR/subtrait-method.rs:67:9
+  --> $DIR/subtrait-method.rs:65:9
    |
 LL |     foo.c();
    |         ^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Baz` defines an item `c`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:27:1
+  --> $DIR/subtrait-method.rs:25:1
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/trait-upcasting/supertraits-modulo-inner-binder.rs b/tests/ui/traits/trait-upcasting/supertraits-modulo-inner-binder.rs
index 6cd74b6c7f7..e65cb60d993 100644
--- a/tests/ui/traits/trait-upcasting/supertraits-modulo-inner-binder.rs
+++ b/tests/ui/traits/trait-upcasting/supertraits-modulo-inner-binder.rs
@@ -1,7 +1,5 @@
 //@ run-pass
 
-#![feature(trait_upcasting)]
-
 trait Super<U> {
     fn call(&self)
     where
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr
index 9a9ad9bbf77..2f27d1522a6 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr
@@ -1,5 +1,5 @@
 error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>`
-  --> $DIR/type-checking-test-1.rs:20:13
+  --> $DIR/type-checking-test-1.rs:18:13
    |
 LL |     let _ = x as &dyn Bar<_>; // Ambiguous
    |             ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr
index 9a9ad9bbf77..2f27d1522a6 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr
@@ -1,5 +1,5 @@
 error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>`
-  --> $DIR/type-checking-test-1.rs:20:13
+  --> $DIR/type-checking-test-1.rs:18:13
    |
 LL |     let _ = x as &dyn Bar<_>; // Ambiguous
    |             ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.rs b/tests/ui/traits/trait-upcasting/type-checking-test-1.rs
index fd902fd87e0..b06f5e04528 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-1.rs
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.rs
@@ -2,8 +2,6 @@
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
 
-#![feature(trait_upcasting)]
-
 trait Foo: Bar<i32> + Bar<u32> {}
 trait Bar<T> {
     fn bar(&self) -> Option<T> {
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-2.rs b/tests/ui/traits/trait-upcasting/type-checking-test-2.rs
index b024b27750b..b4df0f5a902 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-2.rs
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-2.rs
@@ -1,5 +1,3 @@
-#![feature(trait_upcasting)]
-
 trait Foo<T>: Bar<i32> + Bar<T> {}
 trait Bar<T> {
     fn bar(&self) -> Option<T> {
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr
index 3e59b9d3363..f84ea93dc67 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr
@@ -1,11 +1,11 @@
 error[E0605]: non-primitive cast: `&dyn Foo<i32>` as `&dyn Bar<u32>`
-  --> $DIR/type-checking-test-2.rs:19:13
+  --> $DIR/type-checking-test-2.rs:17:13
    |
 LL |     let _ = x as &dyn Bar<u32>; // Error
    |             ^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<_>`
-  --> $DIR/type-checking-test-2.rs:24:13
+  --> $DIR/type-checking-test-2.rs:22:13
    |
 LL |     let a = x as &dyn Bar<_>; // Ambiguous
    |             ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-3.rs b/tests/ui/traits/trait-upcasting/type-checking-test-3.rs
index b2db3a12797..3685569d98d 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-3.rs
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-3.rs
@@ -1,5 +1,3 @@
-#![feature(trait_upcasting)]
-
 trait Foo<'a>: Bar<'a> {}
 trait Bar<'a> {}
 
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr
index 01b8da645f3..d80649638ae 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-3.rs:11:13
+  --> $DIR/type-checking-test-3.rs:9:13
    |
 LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
@@ -7,7 +7,7 @@ LL |     let _ = x as &dyn Bar<'a>; // Error
    |             ^^^^^^^^^^^^^^^^^ cast requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-3.rs:16:18
+  --> $DIR/type-checking-test-3.rs:14:18
    |
 LL | fn test_wrong2<'a>(x: &dyn Foo<'a>) {
    |                -- lifetime `'a` defined here
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-4.rs b/tests/ui/traits/trait-upcasting/type-checking-test-4.rs
index 01759ec7a93..20de722ee9b 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-4.rs
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-4.rs
@@ -1,5 +1,3 @@
-#![feature(trait_upcasting)]
-
 trait Foo<'a>: Bar<'a, 'a> {}
 trait Bar<'a, 'b> {
     fn get_b(&self) -> Option<&'a u32> {
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr
index e91ea193a01..55a5e4cd497 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:19:13
+  --> $DIR/type-checking-test-4.rs:17:13
    |
 LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
@@ -7,7 +7,7 @@ LL |     let _ = x as &dyn Bar<'static, 'a>; // Error
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:24:18
+  --> $DIR/type-checking-test-4.rs:22:18
    |
 LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
@@ -15,7 +15,7 @@ LL |     let _ = x as &dyn Bar<'a, 'static>; // Error
    |                  ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:30:5
+  --> $DIR/type-checking-test-4.rs:28:5
    |
 LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                -- lifetime `'a` defined here
@@ -24,7 +24,7 @@ LL |     y.get_b() // ERROR
    |     ^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:35:5
+  --> $DIR/type-checking-test-4.rs:33:5
    |
 LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                -- lifetime `'a` defined here
@@ -32,7 +32,7 @@ LL |     <_ as Bar>::get_b(x) // ERROR
    |     ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:40:5
+  --> $DIR/type-checking-test-4.rs:38:5
    |
 LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                -- lifetime `'a` defined here
@@ -40,7 +40,7 @@ LL |     <_ as Bar<'_, '_>>::get_b(x) // ERROR
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:48:5
+  --> $DIR/type-checking-test-4.rs:46:5
    |
 LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                -- lifetime `'a` defined here
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-opaques.rs b/tests/ui/traits/trait-upcasting/type-checking-test-opaques.rs
index a3a1ce29465..ab3817da28b 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-opaques.rs
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-opaques.rs
@@ -1,4 +1,4 @@
-#![feature(trait_upcasting, type_alias_impl_trait)]
+#![feature(type_alias_impl_trait)]
 
 //@ check-pass
 
diff --git a/tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs
index 07f1549e177..0548eda0468 100644
--- a/tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs
+++ b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs
@@ -3,7 +3,7 @@
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@check-pass
 
-#![feature(trait_upcasting, type_alias_impl_trait)]
+#![feature(type_alias_impl_trait)]
 
 trait Super {
     type Assoc;
diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr
deleted file mode 100644
index 239f8279194..00000000000
--- a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0658]: cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental
-  --> $DIR/upcast-through-struct-tail.rs:11:5
-   |
-LL |     x
-   |     ^
-   |
-   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
-   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = note: required when coercing `Box<Wrapper<(dyn A + 'a)>>` into `Box<Wrapper<(dyn B + 'a)>>`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr
deleted file mode 100644
index 239f8279194..00000000000
--- a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0658]: cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental
-  --> $DIR/upcast-through-struct-tail.rs:11:5
-   |
-LL |     x
-   |     ^
-   |
-   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
-   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = note: required when coercing `Box<Wrapper<(dyn A + 'a)>>` into `Box<Wrapper<(dyn B + 'a)>>`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs
index e40cca4e0a8..dd4d91f8d4f 100644
--- a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs
+++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs
@@ -1,3 +1,4 @@
+//@ check-pass
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
@@ -9,7 +10,6 @@ trait B {}
 
 fn test<'a>(x: Box<Wrapper<dyn A + 'a>>) -> Box<Wrapper<dyn B + 'a>> {
     x
-    //~^ ERROR cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental
 }
 
 fn main() {}
diff --git a/tests/ui/traits/upcast_reorder.rs b/tests/ui/traits/upcast_reorder.rs
index 55e6ad4c368..43fc1517a3b 100644
--- a/tests/ui/traits/upcast_reorder.rs
+++ b/tests/ui/traits/upcast_reorder.rs
@@ -2,8 +2,6 @@
 //
 // issue: <https://github.com/rust-lang/rust/issues/131813>
 
-#![feature(trait_upcasting)]
-
 trait Pollable {
     #[allow(unused)]
     fn poll(&self) {}
diff --git a/tests/ui/traits/upcast_soundness_bug.rs b/tests/ui/traits/upcast_soundness_bug.rs
index 0ddae1d1417..4c89fa135e7 100644
--- a/tests/ui/traits/upcast_soundness_bug.rs
+++ b/tests/ui/traits/upcast_soundness_bug.rs
@@ -1,4 +1,3 @@
-#![feature(trait_upcasting)]
 //@ check-fail
 //
 // issue: <https://github.com/rust-lang/rust/pull/120222>
diff --git a/tests/ui/traits/upcast_soundness_bug.stderr b/tests/ui/traits/upcast_soundness_bug.stderr
index 19d1a5e5926..f5fa6bdc999 100644
--- a/tests/ui/traits/upcast_soundness_bug.stderr
+++ b/tests/ui/traits/upcast_soundness_bug.stderr
@@ -1,5 +1,5 @@
 error[E0606]: casting `*const dyn Trait<u8, u8>` as `*const dyn Trait<u8, u16>` is invalid
-  --> $DIR/upcast_soundness_bug.rs:59:13
+  --> $DIR/upcast_soundness_bug.rs:58:13
    |
 LL |     let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/wait-forked-but-failed-child.rs b/tests/ui/wait-forked-but-failed-child.rs
index 04f1c1a65d5..4a7f2bee9d9 100644
--- a/tests/ui/wait-forked-but-failed-child.rs
+++ b/tests/ui/wait-forked-but-failed-child.rs
@@ -31,8 +31,17 @@ fn find_zombies() {
     // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html
     let ps_cmd_output = Command::new("ps").args(&["-A", "-o", "pid,ppid,args"]).output().unwrap();
     let ps_output = String::from_utf8_lossy(&ps_cmd_output.stdout);
+    // On AIX, the PPID is not always present, such as when a process is blocked
+    // (marked as <exiting>), or if a process is idle. In these situations,
+    // the PPID column contains a "-" for the respective process.
+    // Filter out any lines that have a "-" as the PPID as the PPID is
+    // expected to be an integer.
+    let filtered_ps: Vec<_> = ps_output
+        .lines()
+        .filter(|line| line.split_whitespace().nth(1) != Some("-"))
+        .collect();
 
-    for (line_no, line) in ps_output.split('\n').enumerate() {
+    for (line_no, line) in filtered_ps.into_iter().enumerate() {
         if 0 < line_no && 0 < line.len() &&
            my_pid == line.split(' ').filter(|w| 0 < w.len()).nth(1)
                          .expect("1st column should be PPID")
diff --git a/tests/ui/weird-exprs.rs b/tests/ui/weird-exprs.rs
index 08b5517aae2..55a8d580a8b 100644
--- a/tests/ui/weird-exprs.rs
+++ b/tests/ui/weird-exprs.rs
@@ -34,7 +34,7 @@ fn what() {
     let i = &Cell::new(false);
     let dont = {||the(i)};
     dont();
-    assert!((i.get()));
+    assert!(i.get());
 }
 
 fn zombiejesus() {
@@ -69,8 +69,8 @@ fn notsure() {
 
 fn canttouchthis() -> usize {
     fn p() -> bool { true }
-    let _a = (assert!((true)) == (assert!(p())));
-    let _c = (assert!((p())) == ());
+    let _a = (assert!(true) == (assert!(p())));
+    let _c = (assert!(p()) == ());
     let _b: bool = (println!("{}", 0) == (return 0));
 }
 
diff --git a/triagebot.toml b/triagebot.toml
index 49cf1213987..3caf4e9fb1e 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -236,6 +236,15 @@ trigger_files = [
     "src/tools/jsondoclint",
 ]
 
+[autolabel."A-attributes"]
+trigger_files = [
+    "compiler/rustc_codegen_ssa/src/codegen_attrs.rs",
+    "compiler/rustc_passes/src/check_attr.rs",
+    "compiler/rustc_attr_parsing",
+    "compiler/rustc_attr_data_structures",
+    "compiler/rustc_attr_validation",
+]
+
 [autolabel."T-compiler"]
 trigger_files = [
     # Source code
@@ -1017,6 +1026,17 @@ cc = ["@ehuss"]
 message = "The rustc-dev-guide subtree was changed. If this PR *only* touches the dev guide consider submitting a PR directly to [rust-lang/rustc-dev-guide](https://github.com/rust-lang/rustc-dev-guide/pulls) otherwise thank you for updating the dev guide with your changes."
 cc = ["@BoxyUwU", "@jieyouxu", "@kobzol"]
 
+[mentions."compiler/rustc_codegen_ssa/src/codegen_attrs.rs"]
+cc = ["@jdonszelmann"]
+[mentions."compiler/rustc_passes/src/check_attr.rs"]
+cc = ["@jdonszelmann"]
+[mentions."compiler/rustc_attr_parsing"]
+cc = ["@jdonszelmann"]
+[mentions."compiler/rustc_attr_data_structures"]
+cc = ["@jdonszelmann"]
+[mentions."compiler/rustc_attr_validation"]
+cc = ["@jdonszelmann"]
+
 [assign]
 warn_non_default_branch.enable = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"